Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it allowed for an enum to have an unlisted value? [duplicate]

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.

like image 319
dragonroot Avatar asked Nov 19 '15 19:11

dragonroot


1 Answers

C++ situation

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:

  • SO question on how to check if an enum value is valid
  • article on avoiding enum out-of-rang in secure coding.
  • Stroutstrup's plaidoyer for scoped enum over unscoped ones

C situation

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.

like image 150
Christophe Avatar answered Sep 19 '22 12:09

Christophe