É uma boa ideia digitar pointers?

Eu olhei através de algum código e notei que a convenção era transformar tipos de ponteiro como

SomeStruct* 

para dentro

 typedef SomeStruct* pSomeStruct; 

Existe algum mérito nisso?

Isso pode ser apropriado quando o ponteiro em si pode ser considerado como uma “checkbox preta”, ou seja, uma parte de dados cuja representação interna deve ser irrelevante para o código.

Essencialmente, se o seu código nunca irá desreferenciar o ponteiro, e você apenas o passar pelas funções da API (algumas vezes por referência), então o typedef não apenas reduz o número de * s no seu código, mas também sugere ao programador que o ponteiro não deveria realmente se intrometer.

Isso também facilita a alteração da API no futuro, se necessário, por exemplo, usando um ID em vez de um ponteiro (ou vice-versa). Como o ponteiro nunca deveria ser desreferenciado em primeiro lugar, o código existente não será quebrado.

Não na minha experiência. Ocultar o ‘ * ‘ torna o código difícil de ler.

A única vez que eu uso um ponteiro dentro do typedef é quando se lida com pointers para funções:

 typedef void (*SigCatcher(int, void (*)(int)))(int); 

 typedef void (*SigCatcher)(int); SigCatcher old = signal(SIGINT, SIG_IGN); 

Caso contrário, acho que eles são mais confusos do que úteis.


A declaração struck-out é o tipo correto para um ponteiro para a function signal() , não para o receptor de sinal. Poderia ser mais claro (usando o tipo SigCatcher corrigido acima) escrevendo:

  typedef SigCatcher (*SignalFunction)(int, SigCatcher); 

Ou, para declarar a function signal() :

  extern SigCatcher signal(int, SigCatcher); 

Ou seja, uma SignalFunction é um ponteiro para uma function que recebe dois argumentos (um int e um SigCatcher ) e retorna um SigCatcher . E o próprio signal() é uma function que recebe dois argumentos (um int e um SigCatcher ) e retorna um SigCatcher .

Isso pode ajudá-lo a evitar alguns erros. Por exemplo, no código a seguir:

 int* pointer1, pointer2; 

pointer2 não é um int * , é simples int . Mas com typedefs isso não vai acontecer:

 typedef int* pInt; pInt pointer1, pointer2; 

Ambos são int * agora.

(Como tantas respostas) depende.

Em C isso é muito comum, pois você está tentando disfarçar que um object é um ponteiro. Você está tentando sugerir que esse é o object que todas as suas funções manipulam (sabemos que é um ponteiro por baixo, mas representa o object que você está manipulando).

 MYDB db = MYDBcreateDB("Plop://djdjdjjdjd"); MYDBDoSomthingWithDB(db,5,6,7); CallLocalFuc(db); // if db is not a pointer things could be complicated. MYDBdestroyDB(db); 

Abaixo do MYDB é provavelmente um ponteiro em algum object.

Em C ++, isso não é mais necessário.
Principalmente porque podemos passar as coisas por referência e os methods são incorporados na declaração de class.

 MyDB db("Plop://djdjdjjdjd"); db.DoSomthingWithDB(5,6,7); CallLocalFuc(db); // This time we can call be reference. db.destroyDB(); // Or let the destructor handle it. 

Isso é uma questão de estilo. Você vê esse tipo de código com muita frequência nos arquivos de header do Windows. Embora eles tendem a preferir a versão maiúscula em vez de prefixar com uma minúscula p.

Pessoalmente, evito esse uso de typedef. É muito mais claro que o usuário diga explicitamente que quer um Foo * do que um PFoo. Os Typedef’s são os mais adequados para tornar o STL legível 🙂

 typedef stl::map> NameToFooMap; 

Typedef é usado para tornar o código mais legível, mas fazer ponteiro como typedef aumentará a confusão. É melhor evitar pointers typedef.

Se você fizer isso, você não poderá criar contêineres STL de const pSomeStruct desde que o compilador lê:

 list structs; 

Como

 list structs; 

que não é um contêiner STL legal, pois os elementos não podem ser atribuídos.

Veja esta questão .

Minha resposta é um claro “não”.

Por quê?

Bem, em primeiro lugar, você simplesmente troca um único caractere * por outro caractere p . Isso é ganho zero . Isso sozinho deve impedir você de fazer isso, pois é sempre ruim fazer coisas extras que são inúteis.

Segundo, e essa é a razão importante, o * carrega significado que não é bom esconder . Se eu passar algo para uma function como esta

 void foo(SomeType bar); void baz() { SomeType myBar = getSomeType(); foo(myBar); } 

Eu não espero que o significado de myBar seja alterado passando-o para foo() . Afinal, eu estou passando por valor, então foo() só vê uma cópia do myBar certo? Não quando SomeType é SomeType para significar algum tipo de ponteiro!

Isso se aplica tanto aos pointers C quanto aos pointers inteligentes C ++: Se você ocultar o fato de que eles são pointers para seus usuários, você criará uma confusão totalmente desnecessária. Então, por favor, não alias seus pointers.

(Eu acredito que o hábito de digitar tipos de ponteiro é apenas uma tentativa equivocada de esconder quantas estrelas você tem como programador http://wiki.c2.com/?ThreeStarProgrammer .)

A API do Win32 faz isso com praticamente todas as estruturas (se não todas)

 POINT => *LPPOINT WNDCLASSEX => *LPWNDCLASSEX RECT => *LPRECT PRINT_INFO_2 => *LPPRINT_INFO_2 

É legal como isso é consistente, mas na minha opinião não acrescenta elegância.

Algum tempo atrás, eu teria respondido “não” a esta pergunta. Agora, com o surgimento de pointers inteligentes, os pointers nem sempre são definidos com uma estrela ‘*’. Portanto, não há nada óbvio sobre um tipo ser um ponteiro ou não.

Então, agora eu diria: não há problema em digitar pointers, desde que fique bem claro que é um “tipo de ponteiro”. Isso significa que você precisa usar um prefixo / sufixo especificamente para isso. Não, “p” não é um prefixo suficiente, por exemplo. Eu provavelmente iria com “ptr”.

Discussão lançada supondo que a linguagem de interesse é C. Ramificações para C ++ não foram consideradas.

Usando um typedef de ponteiro para uma estrutura não marcada

A questão Tamanho de uma estrutura que é definida como um ponteiro gera uma interessante luz lateral sobre o uso de typedef para pointers (de estrutura).

Considere a definição do tipo de estrutura de concreto tagless (não opaca):

 typedef struct { int field1; double field2; } *Information; 

Os detalhes dos membros são completamente tangenciais a essa discussão; tudo o que importa é que este não seja um tipo opaco como typedef struct tag *tag; (e você não pode definir esses tipos opacos por meio de um typedef sem uma tag).

A questão levantada é “como você pode encontrar o tamanho dessa estrutura”?

A resposta curta é ‘somente através de uma variável do tipo’. Não há tags para usar com sizeof(struct tag) . Não é possível escrever sizeof(*Information) , por exemplo, e sizeof(Information *) é o tamanho de um ponteiro para o tipo de ponteiro, não o tamanho do tipo de estrutura.

Na verdade, se você quiser alocar essa estrutura, não será possível criar uma, exceto por meio da alocação dinâmica (ou técnicas substitutas que imitam a alocação dinâmica). Não há como criar uma variável local do tipo de estrutura cujos pointers são chamados de Information , nem existe uma maneira de criar uma variável de escopo de arquivo (global ou static ) do tipo de estrutura, nem existe uma maneira de incorporar tal estrutura (ao contrário de um ponteiro para tal estrutura) em outra estrutura ou tipo de união.

Você pode – deve – escrever:

 Information info = malloc(sizeof(*info)); 

Além do fato de que o ponteiro está oculto no typedef , isso é uma boa prática – se o tipo de info alterado, a alocação de tamanho permanecerá precisa. Mas neste caso, é também a única maneira de obter o tamanho da estrutura e alocar a estrutura. E não há outra maneira de criar uma instância da estrutura.

Isso é prejudicial?

Depende de seus objectives.

Este não é um tipo opaco – os detalhes da estrutura devem ser definidos quando o tipo de ponteiro é typedef ‘d.

É um tipo que só pode ser usado com alocação de memory dinâmica.

É um tipo que é sem nome. O ponteiro para o tipo de estrutura tem um nome, mas o próprio tipo de estrutura não.

Se você quiser impor a alocação dinâmica, isso parece ser uma maneira de fazer isso.

No geral, porém, é mais provável que cause confusão e angústia do que iluminação.

Resumo

Em geral, é uma má idéia usar typedef para definir um ponteiro para um tipo de estrutura sem tag.

A finalidade do typedef é ocultar os detalhes da implementação, mas a definição da propriedade do ponteiro oculta demais e dificulta a compreensão do código. Então, por favor, não faça isso.


Se você quiser ocultar detalhes de implementação (o que geralmente é bom), não oculte a parte do ponteiro. Tomemos por exemplo o protótipo da interface FILE padrão:

 FILE *fopen(const char *filename, const char *mode); char *fgets(char *s, int size, FILE *stream); 

aqui fopen retorna um ponteiro para alguma estrutura FILE (que você não conhece os detalhes de implementação). Talvez o FILE não seja um bom exemplo, porque nesse caso ele poderia ter funcionado com algum tipo de pFILE que escondia o fato de ser um ponteiro.

 pFILE fopen(const char *filename, const char *mode); char *fgets(char *s, int size, pFILE stream); 

No entanto, isso só funcionaria porque você nunca mexeu com o conteúdo que é apontado diretamente. No momento em que você digita algum ponteiro que alguns lugares modificam, o código se torna muito difícil de ler na minha experiência.