typedef struct vs struct definitions [duplicar]


Esta pregunta ya tiene una respuesta aquí:

Soy un principiante en programación en C, pero me preguntaba cuál es la diferencia entre usar typedef al definir una estructura versus no usar typedef. Me parece que realmente no hay diferencia, logran el igual.

struct myStruct{
    int one;
    int two;
};

Vs.

typedef struct{
    int one;
    int two;
}myStruct;
Author: OmG, 2009-11-04

12 answers

El modismo común es usar ambos:

typedef struct X { 
    int x; 
} X;

Son definiciones diferentes. Para hacer la discusión más clara dividiré la oración:

struct S { 
    int x; 
};

typedef struct S S;

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 función del tipo recién definido definiendo el tipo del argumento como struct S:

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

La segunda línea añade un alias de tipo S en el espacio de nombre global y así le permite simplemente escribir:

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

Tenga en cuenta que dado que ambos espacios de nombres 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 creando 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 mantienen en espacios diferentes, pero no puede definir un función con el mismo nombre que un typedef como esos identificadores chocan.

En C++, es ligeramente diferente ya que las reglas para localizar un símbolo han cambiado sutilmente. C++ todavía mantiene los dos espacios de identificador diferentes, pero a diferencia de C, cuando solo se define el símbolo dentro del espacio de identificador de clase, no se requiere que proporcione la palabra clave struct/class:

 // C++
struct S { 
    int x; 
}; // S defined as a class

void f( S a ); // correct: struct is optional

Lo que cambia son las reglas de búsqueda, no dónde se definen los identificadores. El compilador buscará en el identifier table y después de que S no se haya encontrado buscará S dentro de los identificadores de clase.

El código presentado antes se comporta de la misma manera: {[18]]}

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, la estructura S no puede ser resuelta automáticamente por el compilador, y para crear un objeto o definir un argumento de ese tipo debe recurrir a incluir la palabra clave struct:

// previous code here...
int main() {
    S(); 
    struct S s;
}
 820
Author: David Rodríguez - dribeas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-04 20:40:30

struct y typedef son dos cosas muy diferentes.

La palabra clave struct se utiliza 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 fooes una etiqueta ; solo tiene sentido cuando está precedida inmediatamente por la palabra clave struct, porque las etiquetas y otros identificadores están en espacios de nombre distintos. (Esto es similar, pero mucho más restringido que el concepto C++ de namespaces.)

A 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 nombre nuevo para int; my_int y int son exactamente del mismo tipo. Del mismo modo, dada la definición struct anterior, puede escribir:

typedef struct foo foo;

El tipo ya tiene un nombre, struct foo. La declaración typedef da al mismo tipo un nuevo nombre, foo.

La sintaxis le permite combinar un struct y typedef en un solo declaración:

typedef struct bar {
    int n;
} bar;

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

Tenga en cuenta que el nombre typedef no se hace visible hasta el final de la declaración. Si la estructura contiene un puntero a sí misma, 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 programadores 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; el uso de la el mismo nombre es perfectamente legal y hace más 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 se refiere al tipo como struct bar. El typedef guarda un poco de escritura, pero oculta el hecho de que es un tipo de estructura. Si quieres que el tipo sea opaco, esto puede ser algo bueno. Si el código de cliente va a referirse al miembro n por nombre, entonces no es opaco; es visiblemente una estructura, y en mi opinión tiene sentido referirse a ella como una estructura. Pero muchos programadores inteligentes no están de acuerdo conmigo en este punto. Esté preparado para leer y entender el código escrito de cualquier manera.)

(C++ tiene reglas diferentes. Dada una declaración de struct blah, puede referirse al tipo como solo blah, incluso sin un typedef. Usar un typedef podría hacer que tu código C sea un poco más C++like si crees que es algo bueno.)

 93
Author: Keith Thompson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-15 18:02:29

Otra diferencia no señalada es que darle un nombre a la estructura (es decir, struct MyStruct) también le permite proporcionar declaraciones forward de la estructura. Así que 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 te recomiendo es que combines tus dos ejemplos:

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

Esto le da la conveniencia de un nombre de typedef más conciso, pero aún así le permite usar el nombre completo de la estructura si lo necesita.

 85
Author: R Samuel Klatchko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-28 16:34:36

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 en una sola declaración que declara un anónimo struct y typedef s it.

typedef struct { ... } myStruct;
 50
Author: Mehrdad Afshari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-04 17:25:53

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

struct mystruct myvar;

Es ilegal escribir

mystruct myvar;

Si usas el typedef ya no necesitas el prefijo struct.

 24
Author: RED SOFT ADAIR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-10 13:36:08

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

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

Por lo tanto, se recomienda (véase, por ejemplo, la guía de estilo de codificación del kernel de Linux , Capítulo 5) para hacer esto solo cuando en realidad, quiere ocultar esta información y no solo guardar algunas pulsaciones de teclas.

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

 22
Author: Christoph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-05 15:39:17

La diferencia aparece cuando se utiliza el struct.

La primera forma que tienes que hacer:

struct myStruct aName;

La segunda forma le permite eliminar la palabra clave struct.

myStruct aName;
 5
Author: jjnguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-04 17:26:47

No se puede usar la declaración forward con typedef struct.

El struct en sí es un tipo anónimo, por lo que no tiene un nombre real para reenviar la declaración.

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

Una declaración directa como esta no funcionará:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types
 5
Author: Yochai Timmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-10 13:35:09

El typedef, al igual que con otras construcciones, se utiliza para dar un nuevo nombre a un tipo de datos. En este caso se hace principalmente con el fin de hacer el código más limpio:

struct myStruct blah;

Vs.

myStruct blah;
 4
Author: RC.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-04 17:42:55

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

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

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

 4
Author: Wronski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-10 13:35:40

Veo que hay que aclarar esto. C y C++ no definen los tipos de manera diferente. C++ originalmente no era más que un conjunto adicional de inclusiones en la parte superior de C.

El problema que prácticamente todos los desarrolladores de C/C++ tienen hoy en día, es a) las universidades ya no enseñan los fundamentos, y b) la gente no entiende la diferencia entre una definición y una declaración.

La única razón por la que existen tales declaraciones y definiciones es para que el enlazador pueda calcular direccione compensaciones a los campos de la estructura. Esta es la razón por la que la mayoría de la gente se sale con la suya con el código que en realidad está escrito incorrectamente because porque el compilador es capaz de determinar el direccionamiento. El problema surge cuando alguien trata de hacer algo por adelantado, como una cola, o una lista enlazada, o piggying-backing una estructura O/S.

Una declaración comienza con 'struct', una definición comienza con 'typedef'.

Además, una estructura tiene una etiqueta de declaración directa y una etiqueta definida. La mayoría de la gente no sepa esto y use la etiqueta forward declaration como una etiqueta de definición.

Incorrecto:

struct myStruct
   {
   int field_1;
   ...
   };

Acaban de usar la declaración forward para etiquetar la estructura so así que ahora el compilador es consciente de ello but pero no es un tipo definido real. El compilador puede calcular el direccionamiento but pero esta no es la forma en que se pretendía usarlo, por razones que mostraré momentáneamente.

Las personas que utilizan esta forma de declaración, siempre deben poner 'struct' en la práctica cada referencia a ella-- porque no es un nuevo tipo oficial.

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

typedef struct
   {
   field_1;
   ...
   }myStruct;

Ahora es un tipo real, y cuando se puede utilizar como 'myStruct" sin tener que anteponer con la palabra 'struct'.

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

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

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

ADELANTE DECLARACIÓN {

Ahora, aquí están las cosas elegantes, cómo funciona la declaración forward. Si desea crear un tipo que se refiera a sí mismo, como una lista vinculada o un elemento de cola, debe usar una declaración de reenvío. El compilador no considera la estructura definida hasta que llega al punto y coma al final, por lo que solo se declara antes de ese punto.

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

Ahora, el compilador sabe que aunque todavía no sabe cuál es el tipo completo, todavía puede referenciarlo usando el referencia directa.

Por favor declare y escriba sus estructuras correctamente. En realidad hay una razón.

 3
Author: CodeGuru,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-12 18:30:36

Con el último ejemplo se omite la palabra clave struct cuando se usa la estructura. Así que en todas partes de tu código, puedes escribir :

myStruct a;

En lugar de

struct myStruct a;

Esto ahorra algo de escritura, y podría ser más legible, pero esto es una cuestión de gusto

 1
Author: shodanex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-04 17:27:34