2009-02-05 12 views
5

me encontré con un poco de lectura de códigos¿Cuándo no necesito un typedef?

typedef enum eEnum { c1, c2 } tagEnum; 

typedef struct { int i; double d; } tagMyStruct; 

oí rumores de que estas construcciones datan de C. En C++ se puede escribir fácilmente

enum eEnum { c1, c2 }; 
struct MyStruct { int i; double d; }; 

¿Es eso cierto? ¿Cuándo necesitas la primera variante?

Respuesta

10

Primero, ambas declaraciones son legales tanto en C como en C++. Sin embargo, en C, tienen una semántica ligeramente diferente. (En particular, la forma en que se refiere a la estructura más tarde varía).

El concepto clave para entender es que en C, las estructuras existen en un espacio de nombres separado. Todos los tipos incorporados, así como los typedefs existen en el espacio de nombres "predeterminado". Es decir, cuando escribo int, el compilador solo comprueba este espacio de nombres "predeterminado". Si escribo "tagMyStruct" como en su ejemplo, el compilador también solo verifica este espacio de nombres. Pero dependiendo del tipo de declaración que use, la estructura puede no existir en ese espacio de nombres.

Las estructuras son diferentes y existen en un espacio de nombres separado. Así que si hago la siguiente declaración:

struct mystruct {}; 

puedo no simplemente se refieren a ella como MyStruct.En su lugar, tengo que especificar que quiero que el MyStruct que existe en el espacio de nombres estructura:

void foo(struct mystruct bar); // Declare a function which takes a mystruct as its parameter 

que se pone un poco prolijo y torpe en el largo plazo. En su lugar, puede typedef en el espacio de nombres por defecto:

typedef struct mystruct mystruct; // From now on, 'mystruct' in the normal namespace is an alias for 'mystruct' in the struct namespace 

y ahora, mi función puede ser declarada en la forma sencilla:

void foo(mystruct bar); 

Así que su primer ejemplo simplemente se fusiona estos dos pasos juntos: DECLARE una estructura, y poner un alias en el espacio de nombres regular. Y, por supuesto, dado que estamos volviendo a escribirlo de todos modos, no necesitamos el nombre "original", por lo que podemos hacer que la estructura sea anónima. Así que después de su declaración

typedef struct { int i; double d; } tagMyStruct; 

tenemos una estructura sin nombre, que ha sido typedef'ed a 'tagMyStruct' en el espacio de nombres predeterminado.

Eso es como C lo trata. Ambos tipos de declaraciones son válidas, pero una no crea el alias en el espacio de nombres "predeterminado", por lo que debe usar la palabra clave struct cada vez que se refiera al tipo.

En C++, el espacio de nombres estructura separada no existe, por lo que significa la misma cosa. (pero se prefiere la versión más corta).

Editar Para que quede claro, no, C no tiene espacios de nombres. No en el sentido habitual. C simplemente coloca los identificadores en uno de los dos espacios de nombres predefinidos. Los nombres de las estructuras (y las enumeraciones, según recuerdo) se colocan en una, y todos los demás identificadores en otra. Técnicamente, estos son espacios de nombres porque son "contenedores" separados en los que se colocan los nombres para evitar conflictos, pero ciertamente no son espacios de nombres en el sentido C++/C#.

+0

buena explicación – Eclipse

+0

Así C _does_ tienen espacios de nombres! :) Gracias, eso aclara muchas cosas. – xtofl

+0

xtofl: No, en realidad no. No en el sentido C++. las estructuras y los tipos incorporados existen en espacios de nombres separados, pero más allá de eso, no. No puede declarar nuevos espacios de nombres, o cualquier otra cosa que espere. Este es un caso especial. Es probablemente una mala idea pensar en ello como "C tiene espacios de nombres";) – jalf

1

Es solo taquigrafía.

En el segundo caso, declarar la estructura que haría lo mismo con:

struct MyStruct a; 

En la primera variante, que haría lo mismo con:

tagMyStruct a; 
+0

Es taquigrafía en C, también? ¿O solo te refieres a C++? – xtofl

0

La segunda variante también existe en C.

utiliza la primera variante cada vez que desee nombrar a su tipo, por ejemplo:

tagEnum myFunc(tagMyStruct * myArg); 
0

El primero puede ser un inconveniente en C++, ya que no puede reenviarlo declararlo en un archivo de encabezado.

10

En C, si tuviera que escribir

struct MyStruct { int i; double d; }; 

cada vez que quería hacer referencia a ese tipo, habría que especificar que estabas hablando de una estructura:

struct MyStruct instanceOfMyStruct; 
struct MyStruct *ptrToMyStruct; 

Con el versión typedef:

typedef struct { int i; double d; } tagMyStruct; 

es suficiente con escribir:

tagMyStruct instanceOfMyStruct; 
tagMyStruct *ptrToMyStruct; 

La otra gran ventaja con la versión typedef'd es que puede referirse a la estructura de la misma manera tanto en C como en C++, mientras que en la segunda versión se hace referencia diferente en C que en C++.

+0

¿la versión "solo tiene que escribir" sería "tagMyStruct ..." iso "MyStruct"? ¿O es esto correcto? (Que es contrario a la intuición ...) – xtofl

Cuestiones relacionadas