tags:

views:

4439

answers:

7

Are C++ enums signed or unsigned? And by extension is it safe to validate an input by checking that it is <= your max value, and leave out >= your min value (assuming you started at 0 and incremented by 1)?

+1  A: 

The compiler can decide whether or not enums are signed or unsigned.

Another method of validating enums is to use the enum itself as a variable type. For example:

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.
Cristián Romo
+18  A: 

You shouldn't rely on any specific representation. Read the following link. Also, the standard says that it is implementation-defined which integral type is used as the underlying type for an enum, except that it shall not be larger than int, unless some value cannot fit into int or an unsigned int.

In short: you cannot rely on an enum being either signed or unsigned.

zvrba
+2  A: 

You shouldn't depend on them being signed or unsigned. If you want to make them explicitly signed or unsigned, you can use the following:

enum X : signed int { ... };    // signed enum
enum Y : unsigned int { ... };  // unsigned enum
Adam Rosenfield
Only in the future C++0x standard.
dalle
+1  A: 

In the future, with C++0x, strongly typed enumerations will be available and have several advantages (such as type-safety, explicit underlying types, or explicit scoping). With that you could be better assured of the sign of the type.

Kris Kumler
+10  A: 

Let's go to the source. Here's what the C++03 standard (ISO/IEC 14882:2003) document says in 7.2-5 (Enumeration declarations):

The underlying type of an enumeration is an integral type that can represent all the enumerator values defined in the enumeration. It is implementation-defined which integral type is used as the underlying type for an enumeration except that the underlying type shall not be larger than int unless the value of an enumerator cannot fit in an int or unsigned int.

In short, your compiler gets to choose (obviously, if you have negative numbers for some of your ennumeration values, it'll be signed).

Michael Burr
+1 for having RTFM.
Steve Jessop
Getting the standard document PDF is one of the best $30 I've spent.
Michael Burr
+2  A: 

You shouldn't rely on it being either signed or unsigned. According to the standard it is implementation-defined which integral type is used as the underlying type for an enum. In most implementations, though, it is a signed integer.

In C++0x strongly typed enumerations will be added which will allow you to specify the type of an enum such as:

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

Even now, though, some simple validation can be achieved by using the enum as a variable or parameter type like this:

enum Fruit { Apple, Orange };

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.
Matt
+1  A: 

In addition to what others have already said about signed/unsigned, here's what the standard says about the range of an enumerated type:

7.2(6): "For an enumeration where e(min) is the smallest enumerator and e(max) is the largest, the values of the enumeration are the values of the underlying type in the range b(min) to b(max), where b(min) and b(max) are, respectively, the smallest and largest values of the smallest bitfield that can store e(min) and e(max). It is possible to define an enumeration that has values not defined by any of its enumerators."

So for example:

enum { A = 1, B = 4};

defines an enumerated type where e(min) is 1 and e(max) is 4. If the underlying type is signed int, then the smallest required bitfield has 4 bits, and if ints in your implementation are two's complement then the valid range of the enum is -8 to 7. If the underlying type is int, then it has 3 bits and the range is 0 to 7. Check your compiler documentation if you care (for example if you want to cast integral values other than enumerators to the enumerated type, then you need to know whether the value is in the range of the enumeration or not - if not the resulting enum value is unspecified).

Whether those values are valid input to your function may be a different issue from whether they are valid values of the enumerated type. Your checking code is probably worried about the former rather than the latter, and so in this example should at least be checking >=A and <=B.

Steve Jessop