2011-12-21 15 views
17

Vea el ejemplo simple a continuación. Cuando una función que devuelve un enum se asigna a una variable de enum diferente, no recibo ninguna advertencia, incluso con gcc -Wall -pedantic. ¿Por qué no es posible que un compilador de C haga una verificación de tipo en enum s? ¿O es gcc específico? No tengo acceso a cualquier otro compilador en este momento para probarlo ..verificación de tipo enum en C/gcc

enum fruit { 
APPLE, 
ORANGE 
}; 

enum color { 
RED, 
GREEN 
}; 

static inline enum color get_color() { 
    return RED; 
} 

int main() { 
    enum fruit ftype; 
    ftype = get_color(); 
} 

Respuesta

26

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.)

2

Eso es porque enum s en C son simplemente un grupo de constantes enteras únicas, que se salvó de tener que #define un manojo entero de constantes. No es como C++ donde los enum que usted crea son de un tipo específico. Así es como C es.

También vale la pena señalar que el tamaño real utilizado para representar enum valores depende del compilador.

1

Una enumeración en C se maneja básicamente como un número entero. Es solo una forma más agradable de usar constantes.

// this would work as well 
    ftype = 1; 

También puede especificar los valores:

enum color { 
    RED=0,GREEN,BLUE 
    } mycolor; 

    mycolor = 1; // GREEN 
3

gcc decidió no advertir (como lo hace clang) pero icc (compilador de Intel) advertiría en esta situación. Si desea verificar tipos adicionales para los tipos enum, puede pasar su código a algún software de comprobación de código estático como Lint que pueda advertir en tales casos.

gcc decidió que no era útil para advertir para las conversiones implícitas entre enum tipos sino también nota de que C no requiere la puesta en práctica de emitir un diagnóstico en el caso de una cesión entre dos diferentes tipos enum. Esto es lo mismo que para la asignación entre cualquier tipo aritmético: el diagnóstico no es requerido por C. Por ejemplo, gcc tampoco avisaría si asigna un long long a un char o un short a un long.

5

Probablemente la mayoría de nosotros comprenda las causas subyacentes ("la especificación dice que debe funcionar"), pero también estamos de acuerdo en que esto es la causa de muchos errores de programación en "C" y que la solución de envoltura de estructuras es bruto. Haciendo caso omiso de las comprobaciones complementarias como la pelusa, esto es lo que tenemos:

gcc (4.9): No warning available. 
microsoft cl (18.0): No warning available. 
clang (3.5): YES -Wenum-conversion 
+0

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. –