typedef struct vs struct definitions

Soy un principiante en la progtwigción C, pero me preguntaba cuál es la diferencia entre usar typedef al definir una estructura y no usar typedef. Me parece que en realidad no hay diferencia, ellos logran lo mismo.

struct myStruct{ int one; int two; }; 

vs.

 typedef struct{ int one; int two; }myStruct; 

La expresión común es usar ambos:

 typedef struct X { int x; } X; 

Son diferentes definiciones. Para aclarar la discusión, dividiré la oración:

 struct S { int x; }; typedef struct SS; 

En la primera línea está definiendo el identificador S dentro del espacio de nombre de la estructura (no en el sentido de C ++). Puede usarlo y definir variables o argumentos de funciones del tipo recientemente definido al definir el tipo del argumento como struct S :

 void f( struct S argument ); // struct is required here 

La segunda línea agrega un alias de tipo S en el espacio de nombre global y, por lo tanto, le permite escribir:

 void f( S argument ); // struct keyword no longer needed 

Tenga en cuenta que dado que los dos espacios de nombre de identificador son diferentes, definir S tanto en las estructuras como en los espacios globales no es un error, ya que no está redefiniendo el mismo identificador, sino que crea un identificador diferente en un lugar diferente.

Para hacer la diferencia más clara:

 typedef struct S { int x; } T; void S() { } // correct //void T() {} // error: symbol T already defined as an alias to 'struct S' 

Puede definir una función con el mismo nombre de la estructura ya que los identificadores se guardan en espacios diferentes, pero no puede definir una función con el mismo nombre que un typedef cuando esos identificadores colisionan.

En C ++, es ligeramente diferente ya que las reglas para ubicar un símbolo han cambiado sutilmente. C ++ aún conserva los dos espacios identificadores diferentes, pero a diferencia de C, cuando solo defines el símbolo dentro del espacio identificador de clase, no es necesario que proporciones la palabra clave struct / class:

  // C++ struct S { int x; }; // S defined as a class void f( S a ); // correct: struct is optional 

¿Qué cambios son las reglas de búsqueda, no donde se definen los identificadores? El comstackdor buscará en la tabla de identificador global y después de que no se haya encontrado S , buscará S dentro de los identificadores de clase.

El código presentado antes se comporta de la misma manera:

 typedef struct S { int x; } T; void S() {} // correct [*] //void T() {} // error: symbol T already defined as an alias to 'struct S' 

Después de la definición de la función S en la segunda línea, el comstackdor no puede resolver automáticamente la estructura S, y para crear un objeto o definir un argumento de ese tipo debe volver a incluir la palabra clave struct :

 // previous code here... int main() { S(); struct S s; } 

struct y typedef son dos cosas muy diferentes.

La palabra clave struct se usa para definir, o para referirse a, un tipo de estructura. Por ejemplo, esto:

 struct foo { int n; }; 

crea un nuevo tipo llamado struct foo . El nombre foo es una etiqueta ; solo tiene sentido cuando está precedido inmediatamente por la palabra clave struct , porque las tags y otros identificadores se encuentran en espacios de nombres distintos. (Esto es similar a, pero mucho más restringido que, el concepto de namespace de namespace C ++).

Un typedef , a pesar del nombre, no define un nuevo tipo; simplemente crea un nuevo nombre para un tipo existente. Por ejemplo, dado:

 typedef int my_int; 

my_int es un nuevo nombre para int ; my_int y int son exactamente del mismo tipo. Del mismo modo, dada la definición de struct anterior, puede escribir:

 typedef struct foo foo; 

El tipo ya tiene un nombre, struct foo . La statement typedef le da al mismo tipo un nuevo nombre, foo .

La syntax le permite combinar una struct y typedef en una sola statement:

 typedef struct bar { int n; } bar; 

Este es un modismo común. Ahora puede referirse a este tipo de estructura ya sea como struct bar o simplemente como bar .

Tenga en cuenta que el nombre typedef no se vuelve visible hasta el final de la statement. Si la estructura contiene un puntero a sí mismo, debe usar la versión struct para referirse a ella:

 typedef struct node { int data; struct node *next; /* can't use just "node *next" here */ } node; 

Algunos progtwigdores usarán identificadores distintos para la etiqueta struct y para el nombre typedef. En mi opinión, no hay una buena razón para eso; usar el mismo nombre es perfectamente legal y deja en claro que son del mismo tipo. Si debe usar identificadores diferentes, al menos use una convención consistente:

 typedef struct node_s { /* ... */ } node; 

(Personalmente, prefiero omitir el typedef y referirme al tipo como struct bar . El typedef guarda un poco de tipeo, pero oculta el hecho de que es un tipo de estructura. Si quieres que el tipo sea opaco, esto puede ser bueno Si el código del cliente se va a referir al miembro n por nombre, entonces no es opaco, es visiblemente una estructura y, en mi opinión, tiene sentido referirse a él como una estructura. Pero muchos progtwigdores inteligentes no están de acuerdo conmigo. en este punto. Esté preparado para leer y comprender el código escrito de cualquier manera).

(C ++ tiene reglas diferentes. Dada una statement de struct blah , puede referirse al tipo como simplemente blah , incluso sin un typedef. Usar un typedef podría hacer que su código C sea un poco más parecido a C ++, si cree que es bueno cosa.)

Otra diferencia no señalada es que darle a la estructura un nombre (es decir, struct myStruct) también le permite proporcionar declaraciones de la estructura. Entonces, en algún otro archivo, podrías escribir:

 struct myStruct; void doit(struct myStruct *ptr); 

sin tener que tener acceso a la definición. Lo que recomiendo es que combine sus dos ejemplos:

 typedef struct myStruct{ int one; int two; } myStruct; 

Esto le brinda la conveniencia del nombre typedef más conciso pero aún le permite usar el nombre completo de la estructura si lo necesita.

En C (no en C ++), debe declarar variables de estructura como:

 struct myStruct myVariable; 

Para poder usar myStruct myVariable; en su lugar, puede typedef la estructura:

 typedef struct myStruct someStruct; someStruct myVariable; 

Puede combinar struct definición y typedef s it en una sola statement que declara una struct anónima y typedef s it.

 typedef struct { ... } myStruct; 

Si usas struct sin typedef , siempre tendrás que escribir

 struct mystruct myvar; 

Es ilegal escribir

 mystruct myvar; 

Si usa typedef ya no necesita el prefijo struct .

En C, las palabras clave del especificador de tipo de estructuras, uniones y enumeraciones son obligatorias, es decir, siempre debe anteponer el nombre del tipo (su etiqueta ) a struct , union o enum al referirse al tipo.

Puede deshacerse de las palabras clave utilizando un typedef , que es una forma de ocultación de información ya que el tipo real de un objeto ya no será visible al declararlo.

Por lo tanto, se recomienda (consulte, por ejemplo, la guía de estilo de encoding del kernel de Linux , Capítulo 5) hacer esto solo cuando realmente desee ocultar esta información y no solo para guardar unas pocas teclas.

Un ejemplo de cuándo debería usar un typedef sería un tipo opaco que solo se utiliza con las funciones / macros de acceso correspondientes.

La diferencia aparece cuando usas la struct .

La primera forma que tienes que hacer:

 struct myStruct aName; 

La segunda forma le permite eliminar la palabra clave struct .

 myStruct aName; 

No puede usar la statement forward con la typedef struct .

La struct sí es anónima, por lo que no tiene un nombre real para reenviar declarar.

 typedef struct{ int one; int two; } myStruct; 

Una statement directa como esta no funcionará:

 struct myStruct; //forward declaration fails void blah(myStruct* pStruct); //error C2371: 'myStruct' : redefinition; different basic types 

El typedef , como lo es con otras construcciones, se usa para dar un nuevo nombre a un tipo de datos. En este caso, se realiza principalmente para que el código sea más limpio:

 struct myStruct blah; 

vs.

 myStruct blah; 

El siguiente código crea una estructura anónima con el alias myStruct :

 typedef struct{ int one; int two; } myStruct; 

No puede referirlo sin el alias porque no especifica un identificador para la estructura.

Veo que hay alguna aclaración en orden sobre esto. C y C ++ no definen tipos de manera diferente. C ++ originalmente no era más que un conjunto adicional de incluye en la parte superior de C.

El problema que prácticamente todos los desarrolladores de C / C ++ tienen hoy, es a) las universidades ya no enseñan los fundamentos, yb) las personas no entienden la diferencia entre una definición y una statement.

La única razón por la que existen tales declaraciones y definiciones es para que el vinculador pueda calcular las compensaciones de dirección en los campos de la estructura. Esta es la razón por la cual la mayoría de las personas se salen con la suya con un código que en realidad está escrito incorrectamente, porque el comstackdor puede determinar el direccionamiento. El problema surge cuando alguien intenta hacer algo por adelantado, como una cola o una lista vinculada, o piggying-backing de una estructura de O / S.

Una statement comienza con ‘struct’, una definición comienza con ‘typedef’.

Además, una estructura tiene una etiqueta de statement directa y una etiqueta definida. La mayoría de las personas no saben esto y usan la etiqueta de statement directa como una etiqueta de definición.

Incorrecto:

 struct myStruct { int field_1; ... }; 

Acaban de utilizar la statement directa para etiquetar la estructura, de modo que ahora el comstackdor está al tanto, pero no es un tipo definido real. El comstackdor puede calcular el direccionamiento, pero esta no es la intención de su uso, por razones que mostraré momentáneamente.

Las personas que usan esta forma de statement, siempre deben poner ‘struct’ prácticamente en cada referencia, porque no es un nuevo tipo oficial.

En cambio, cualquier estructura que no se refiera a sí misma, debe declararse y definirse solo de esta manera:

 typedef struct { field_1; ... }myStruct; 

Ahora es un tipo real, y cuando lo usas puedes usar como ‘myStruct’ sin tener que precederlo con la palabra ‘struct’.

Si desea una variable de puntero a esa estructura, incluya una etiqueta secundaria:

 typedef struct { field_1; ... }myStruct,*myStructP; 

Ahora tiene una variable de puntero a esa estructura, personalizada para ella.

DECLARACIÓN ADELANTE

Ahora, estas son las cosas elegantes, cómo funciona la statement directa. Si desea crear un tipo que se refiera a sí mismo, como una lista enlazada o un elemento de cola, debe usar una statement directa. El comstackdor no considera la estructura definida hasta que llega al punto y coma al final, por lo que acaba de declararse antes de ese punto.

 typedef struct myStructElement { myStructElement* nextSE; field_1; ... }myStruct; 

Ahora, el comstackdor sabe que aunque todavía no sabe qué tipo de todo es, aún puede hacer referencia a él utilizando la referencia directa.

Por favor, declare y defina sus estructuras correctamente. De hecho, hay una razón.

Con el último ejemplo omite la palabra clave struct al usar la estructura. Entonces, en cualquier lugar de tu código, puedes escribir:

 myStruct a; 

en lugar de

 struct myStruct a; 

Esto ahorra algo de tipeo, y puede ser más legible, pero esto es una cuestión de gusto