¿Las enums de C ++ están firmadas o sin firmar?

¿Las enums de C ++ están firmadas o sin firmar? Y por extensión, ¿es seguro validar una entrada comprobando que es = su valor mínimo (suponiendo que comenzó en 0 y se incrementó en 1)?

No debe confiar en ninguna representación específica. Lee el siguiente enlace . Además, el estándar dice que está definido por implementación qué tipo integral se utiliza como el tipo subyacente para una enumeración, excepto que no debe ser mayor que int, a menos que algún valor no pueda caber en int o unsigned int.

En resumen: no puede confiar en que una enumeración sea firmada o no.

Vayamos a la fuente. Esto es lo que dice el documento estándar C ++ 03 (ISO / IEC 14882: 2003) en 7.2-5 (Declaraciones de enumeración):

El tipo subyacente de una enumeración es un tipo integral que puede representar todos los valores del enumerador definidos en la enumeración. Está definido por implementación qué tipo integral se utiliza como el tipo subyacente para una enumeración, excepto que el tipo subyacente no debe ser mayor que int a menos que el valor de un enumerador no pueda caber en una int o unsigned int.

En resumen, tu comstackdor puede elegir (obviamente, si tienes números negativos para algunos de tus valores de enumeración, se firmará).

No debe depender de que estén firmados o sin firmar. Si desea que estén explícitamente firmados o sin firmar, puede usar lo siguiente:

enum X : signed int { ... }; // signed enum enum Y : unsigned int { ... }; // unsigned enum 

No debe confiar en que sea firmado o sin firmar. De acuerdo con el estándar, está definido por implementación qué tipo integral se utiliza como el tipo subyacente para una enumeración. En la mayoría de las implementaciones, sin embargo, es un número entero con signo.

En C ++ 0x se agregarán enumeraciones fuertemente tipadas que le permitirán especificar el tipo de una enumeración tal como:

 enum X : signed int { ... }; // signed enum enum Y : unsigned int { ... }; // unsigned enum 

Incluso ahora, sin embargo, se puede lograr una validación simple usando la enumeración como una variable o tipo de parámetro como este:

 enum Fruit { Apple, Banana }; enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum fruitVariable = 1; // Error, 1 is not a member of enum Fruit // even though it has the same value as banana. 

El comstackdor puede decidir si las enumeraciones están o no firmadas.

Otro método para validar enumeraciones es usar la enumeración misma como un tipo de variable. Por ejemplo:

 enum Fruit { Apple = 0, Banana, Pineapple, Orange, Kumquat }; enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum fruitVariable = 1; // Error, 1 is not a member of enum Fruit even though it has the same value as banana. 

Incluso algunas viejas respuestas obtuvieron 44 votaciones ascendentes, yo tiendo a estar en desacuerdo con todas ellas. En resumen, no creo que debamos preocuparnos por el underlying type de la enumeración.

En primer lugar, C ++ 03 tipo Enum es un tipo distinto que no tiene ningún concepto de signo. Desde el estándar C ++ 03 dcl.enum

 7.2 Enumeration declarations 5 Each enumeration defines a type that is different from all other types.... 

Entonces, cuando estamos hablando del signo de un tipo enum, digamos al comparar 2 operandos de enum usando el operador < , en realidad estamos hablando de convertir implícitamente el tipo enum a algún tipo integral. Es el signo de este tipo integral lo que importa . Y al convertir enum al tipo integral, se aplica esta statement:

 9 The value of an enumerator or an object of an enumeration type is converted to an integer by integral promotion (4.5). 

Y, aparentemente, el tipo subyacente de la enumeración no tiene nada que ver con la Promoción Integral. Dado que el estándar define la Promoción Integral de esta manera:

 4.5 Integral promotions conv.prom .. An rvalue of an enumeration type (7.2) can be converted to an rvalue of the first of the following types that can represent all the values of the enumeration (ie the values in the range bmin to bmax as described in 7.2: int, unsigned int, long, or unsigned long. 

Por lo tanto, si un tipo enum se convierte en signed int o unsigned int depende de si signed int puede contener todos los valores de los enumeradores definidos, no el tipo subyacente de la enumeración.

Ver mi pregunta relacionada Signo de C ++ Enum tipo incorrecto después de convertir a tipo integral

En el futuro, con C ++ 0x, las enumeraciones fuertemente tipadas estarán disponibles y tendrán varias ventajas (como seguridad de tipo, tipos subyacentes explícitos o scope explícito). Con eso, podrías estar más seguro del signo del tipo.

Además de lo que otros ya han dicho sobre firmar / firmar, esto es lo que dice la norma sobre el rango de un tipo enumerado:

7.2 (6): “Para una enumeración donde e (min) es el enumerador más pequeño y e (máximo) es el más grande, los valores de la enumeración son los valores del tipo subyacente en el rango b (min) a b (máx. ), donde b (min) yb (max) son, respectivamente, los valores más pequeños y más grandes del bitfield más pequeño que puede almacenar e (min) y e (max). Es posible definir una enumeración que tiene valores no definidos por cualquiera de sus enumeradores “.

Así por ejemplo:

 enum { A = 1, B = 4}; 

define un tipo enumerado donde e (min) es 1 y e (máximo) es 4. Si el tipo subyacente está firmado int, entonces el bitfield más pequeño requerido tiene 4 bits, y si ints en su implementación son complemento de dos, entonces el rango válido de la enumeración es de -8 a 7. Si el tipo subyacente no está firmado, entonces tiene 3 bits y el rango es de 0 a 7. Compruebe la documentación del comstackdor si le importa (por ejemplo, si desea convertir valores integrales que no sean enumeradores en el tipo enumerado, entonces necesita saber si el valor está en el rango de la enumeración o no; de lo contrario, el valor enum resultante no está especificado).

Si esos valores son entradas válidas para su función puede ser un problema diferente de si son valores válidos del tipo enumerado. Es probable que su código de comprobación esté preocupado por el primero y no por el último, por lo que en este ejemplo, al menos, debería verificar> = A y <= B.