Say, we have
enum E { Foo = 0, Bar = 1 };
Now, we do
enum E v = ( enum E ) 2;
And then
switch ( v ) { case Foo: doFoo(); break; case Bar: doBar(); break; default: // Is the compiler required to honor this? doOther(); break; }
Since the switch above handles every possible listed value of the enum, is it allowed for the compiler to optimize away the default
branch above, or otherwise have an unspecified or undefined behavior in the case the value of enum is not in the list?
As I am expecting that the behavior should be similar for C and C++, the question is about both languages. However, if there's a difference between C and C++ for that case, it would be nice to know about it, too.
In C++, each enum has an underlying integral type. It can be fixed, if it is explicitly specified (ex: enum test2 : long { a,b};
) or if it is int
by default in the case of a scoped enum (ex: enum class test { a,b };
):
[dcl.enum]/5: Each enumeration defines a type that is different from all other types. Each enumeration also has an underlying type. (...) if not explicitly specified, the underlying type of a scoped enumeration type is int. In these cases, the underlying type is said to be fixed.
In the case of an unscoped enum where the underlying type was not explicitely fixed (your example), the standard gives more flexibility to your compiler:
[dcl.enum]/7: For an enumeration whose underlying type is not fixed, the underlying type 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 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.
Now a very tricky thing: the values that can be held by an enum variable depends on whether or not the underlying type is fixed:
if it's fixed, "the values of the enumeration are the values of the underlying type."
otherwhise, it is the integral values within the minimum and the maximum of the smallest bit-field that can hold the smallest enumerator and the largest one.
You are in the second case, although your code will work on most compilers, the smalest bitfield has a size of 1 and so the only values that you can for sure hold on all compliant C++ compilers are those between 0 and 1...
Conclusion: If you want to ensure that the value can be set to 2, you either have to make your enum a scoped enum, or explicitly indicate an underlying type.**
More reading:
The C situation is much simpler (C11):
6.2.5/16: An enumeration comprises a set of named integer constant values. Each distinct enumeration constitutes a different enumerated type.
So basically, it is an int:
6.7.2.2./2 The expression that defines the value of an enumeration constant shall be an integer constant expression that has a value representable as an int.
With the following restriction:
Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, but shall be capable of representing the values of all the members of the enumeration.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With