¿Por qué usas typedef cuando declaras una enumeración en C ++?


183

No he escrito ningún C ++ en años y ahora estoy tratando de volver a escribirlo. Luego me encontré con esto y pensé en renunciar:

typedef enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

¿Que es esto? ¿Por qué se typedefusa la palabra clave aquí? ¿Por qué aparece el nombre TokenTypedos veces en esta declaración? ¿En qué se diferencia la semántica de esto?

enum TokenType
{
    blah1 = 0x00000000,
    blah2=0x01000000,
    blah3=0x02000000
};

Respuestas:


156

En C, declarar su enumeración de la primera manera le permite usarla así:

TokenType my_type;

Si usa el segundo estilo, se verá obligado a declarar su variable de esta manera:

enum TokenType my_type;

Como lo mencionaron otros, esto no hace una diferencia en C ++. Supongo que la persona que escribió esto es un programador C en el fondo o está compilando código C como C ++. De cualquier manera, no afectará el comportamiento de su código.


12
Su pregunta es correcta solo para C, pero no para C ++. En C ++, las enumeraciones y estructuras se pueden usar directamente como si hubiera una definición de tipo
David Rodríguez - dribeas

77
Bueno, sí, pero esto responde a la verdadera pregunta que se hizo, que era realmente sobre "¿qué significa esto?"
BobbyShaftoe

Entonces, ¿es técnicamente un typedef o una enumeración?
Miek

55
Son ambos. También podría decir: enum TokenType_ {...}; typedef enum TokenType_ TokenType;
Ryan Fox

La respuesta está completa, pero creo que el punto es que el TokenType; después de la declaración enum es lo que está declarando el nombre del tipo. Por lo tanto, la respuesta no está 100% completa. Declarar 'la primera forma' especifica AMBOS una enumeración y un nuevo nombre de tipo que es esa enumeración en un blob de sintaxis. Entonces la respuesta fue útil, pero creo que podría mejorarse un poco. Tal vez fui demasiado duro para rechazar el voto. Entonces lo voté después de todo eso. Si estuviera realmente seguro de mí mismo, tomaría un botín para editar / mejorar la respuesta ... pero esta es una respuesta bastante buena
Ross Youngblood

97

Es una herencia C, en C, si haces:

enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
};

tendrás que usarlo haciendo algo como:

enum TokenType foo;

Pero si haces esto:

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

Podrás declarar:

TokenType foo;

Pero en C ++, puede usar solo la definición anterior y usarla como si estuviera en una definición de tipo C.


1
Lo que dices es cierto en C. No es cierto en C ++.
Jonathan Leffler

49
¿No es lo que dije en mi última oración?
mat

2
@mat Voté tu comentario sobre la última oración, pero para ser justos, está mal redactado y es confuso.
AR

20

No necesitas hacerlo. En C (no en C ++) se le pidió que utilizara Enumname Enumname para referirse a un elemento de datos del tipo enumerado. Para simplificarlo se dejen a typedef a un solo tipo nombre de los datos.

typedef enum MyEnum { 
  //...
} MyEnum;

funciones permitidas que toman un parámetro de la enumeración para definirse como

void f( MyEnum x )

en lugar del más largo

void f( enum MyEnum x )

Tenga en cuenta que el nombre del nombre de tipo no necesita ser igual al nombre de la enumeración. Lo mismo sucede con las estructuras.

En C ++, por otro lado, no es obligatorio, ya que se puede acceder a las enumeraciones, clases y estructuras directamente como tipos por sus nombres.

// C++
enum MyEnum {
   // ...
};
void f( MyEnum x ); // Correct C++, Error in C

En realidad, creo que esta puede ser una mejor respuesta que la generalmente aceptada, ya que explica claramente "por qué" es diferente.
Ross Youngblood

11

En C, es un buen estilo porque puede cambiar el tipo a algo además de una enumeración.

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

foo(enum e_TokenType token);  /* this can only be passed as an enum */

foo(TokenType token); /* TokenType can be defined to something else later
                         without changing this declaration */

En C ++ puede definir la enumeración para que se compile como C ++ o C.


¿No quieres decir In C++ you can *typedef* the enum so that it will compile as C++ or C.? Usted dijo: In C++ you can define the enum so that it will compile as C++ or C.Observe cómo he cambiado de definea typedef. Bueno ... supongo typedefing está definiendo.
Gabriel Staples

6

Remanente de C.


No sé si el calificador 'temprano' es relevante; aún escribirías eso en C si quisieras usar el nombre del tipo sin el prefijo enum.
Jonathan Leffler

1
cierto. Lo borraré No he seguido la especificación C durante mucho, mucho tiempo. Fui demasiado vago para verificar la distinción c / c ++ ... -1 para mí.
Tim

6

Algunas personas dicen que C no tiene espacios de nombres, pero eso no es técnicamente correcto. Tiene tres:

  1. Etiquetas ( enum, uniony struct)
  2. Etiquetas
  3. (todo lo demas)

typedef enum { } XYZ;declara una enumeración anónima y la importa al espacio de nombres global con el nombre XYZ.

typedef enum ABC { } XYZ;declara una enumeración nombrada ABCen el espacio de nombres de la etiqueta, luego la importa al espacio de nombres global como XYZ.

Algunas personas no quieren molestarse con los espacios de nombres separados, por lo que escriben todo. Otros nunca escriben def porque quieren el espacio de nombres.


Esto no es exactamente exacto. Se hace referencia a las estructuras, uniones y enumeraciones por nombre de etiqueta (a menos que sea anónimo, como usted mencionó). Hay espacios de nombres separados para tipos y etiquetas. Puede tener un tipo con exactamente el mismo nombre que una etiqueta y compilar bien. Sin embargo, si una enumeración tiene la misma etiqueta que una estructura, este es un error de compilación exactamente como lo serían 2 estructuras o 2 enumeraciones con la misma etiqueta. También está olvidando que las etiquetas para ir a son un espacio de nombres separado. Una etiqueta puede ser el mismo nombre que una etiqueta, o un identificador, pero no un tipo, y un identificador puede tener el mismo nombre que una etiqueta, pero no un tipo.
Rich Jahn el

3

Esto es un poco viejo, pero de todos modos, espero que aprecies el enlace que estoy a punto de escribir como lo aprecié cuando lo encontré a principios de este año.

Aquí se trata . Debo citar la explicación que siempre tengo en mente cuando tengo que entender algunos tipos de letra desagradables:

En las declaraciones de variables, los nombres introducidos son instancias de los tipos correspondientes. [...] Sin embargo, cuando la typedefpalabra clave precede a la declaración, los nombres introducidos son alias de los tipos correspondientes

Como mucha gente dijo anteriormente, no hay necesidad de usar typedefs declarando enumeraciones en C ++ . ¡Pero esa es la explicación de la sintaxis de typedef! Espero que ayude (probablemente no OP, ya que han pasado casi 10 años, pero cualquiera que esté luchando por entender este tipo de cosas).


1

En alguna guía de estilo de código C se dice que la versión typedef es la preferida por "claridad" y "simplicidad". No estoy de acuerdo, porque typedef ofusca la naturaleza real del objeto declarado. De hecho, no uso typedefs porque al declarar una variable C quiero tener claro qué es realmente el objeto. Esta opción me ayuda a recordar más rápido lo que realmente hace un viejo código y ayudará a otros a mantener el código en el futuro.


1

La respuesta real a la pregunta "por qué" (que sorprendentemente es ignorada por las respuestas existentes sobre esta vieja pregunta) es que esta enumdeclaración probablemente se encuentra en un archivo de encabezado que está destinado a ser compilable como código C y C ++ (es decir, incluido en los archivos de implementación C y C ++). El arte de escribir dichos archivos de encabezado se basa en la capacidad del autor para seleccionar características de idioma que tengan el significado compatible adecuado en ambos idiomas.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.