Esta declaración:
enum fruit {
apple,
orange
};
declara tres cosas: un tipo llamado enum fruit
, y dos encuestadores llaman apple
y orange
.
enum fruit
es realmente un tipo distinto. Es compatible con algún tipo de entero definido por la implementación; por ejemplo, enum fruit
podría ser compatible con int
, con char
, o incluso con unsigned long long
si la implementación lo elige, siempre que el tipo elegido pueda representar todos los valores.
Los enumeradores, por otro lado, son constantes del tipo int
. De hecho, hay un truco común de utilizar un desnudo declaración enum
declarar int
constantes sin necesidad de utilizar el preprocesador:
enum { MAX = 1000 };
Sí, eso significa que la constante apple
, a pesar de que fue declarada como parte de la definición de enum fruit
, en realidad no es del tipo enum fruit
. Las razones para esto son históricas. Y sí, probablemente hubiera tenido más sentido que los enumeradores fueran constantes del tipo.
En la práctica, esta inconsistencia raramente importa mucho. En la mayoría de los contextos, los tipos discretos (es decir, los tipos de enteros y enumeraciones) son en gran parte intercambiables, y las conversiones implícitas generalmente hacen lo correcto.
enum fruit { apple, orange };
enum fruit obj; /* obj is of type enum fruit */
obj = orange; /* orange is of type int; it's
implicitly converted to enum fruit */
if (obj == orange) { /* operands are converted to a common type */
/* ... */
}
Pero el resultado es que, como hemos visto, el compilador no es probable que le avise si se utiliza una constante asociada con un tipo enumerado cuando quiere decir a utilizar uno diferente.
Una forma de obtener una fuerte verificación de tipos es envolver sus datos en una estructura:
enum fruit { /* ... */ };
enum color { /* ... */ };
struct fruit { enum fruit f; };
struct color { enum color c; };
struct fruit
y struct color
son tipos distintos e incompatibles con ninguna conversión implícita (o explícita) entre ellos. El inconveniente es que debe consultar el miembro .f
o .c
explícitamente. (La mayoría de los programadores de C solo cuentan con su capacidad de hacer las cosas bien, en primer lugar, con resultados mixtos)
(typedef
) no le da una verificación de tipo fuerte; a pesar del nombre, crea un alias para un tipo, no es un nuevo tipo.)
(Las reglas en C++ son un poco diferentes.)
Todo hail Apple/LLVM. Creo que estos 3 compiladores cubren casi todos los sistemas operativos principales (iOS, Android, Microsoft, OSX), pero se agradecen otras actualizaciones interesantes. Creo que una publicación anterior menciona icc, pero no tengo acceso a eso. –