7

What value does an enumeration object have if it is set to a value not equal to any of its respective enumeration constants?

Consider the following code:

enum foobar{
    FOO = 1,
    BAR = 5
};

enum foobar baz = 5;
enum foobar qux = 42;

The variable baz is set to the integer value 5, while the variable qux is set to the integer value 42.

I suspect the variable baz will hold the value BAR, but I'm unsure about the variable qux. No enumeration constant was assigned the value 42, so what happens when an enum foobar variable is set to such a value?

Is the C99 standard explicit about the outcome?

Vilhelm Gray
  • 11,516
  • 10
  • 61
  • 114

3 Answers3

6

Variable qux is not going to hold any of the enums values. Its value will be equal to 42 in the underlying type the compiler selects to represent foobar, which is implementation-defined. This would not present a problem when the value is 42, but it may become an issue when the constant does not fit in the type selected by the compiler for your enumeration.

One of the reasons why the compiler allows assignments of values other than enum constants is to support "flag" enumerations, when constants are expected to be combined in bitwise operations:

enum foobar {
    foo = 1
,   bar = 2
,   baz = 4
} test = (foo | baz);

Variable test above holds the value of 5, which does not correspond to any of the enum constants.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

The C99 draft standard does not seem to restrict an enumerator to take on values of its members exclusively but it does say that the enumerators underlying type shall be capable of representing the values of all its members. This is covered in section 6.7.2.2 Enumeration specifiers:

Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined,110) but shall be capable of representing the values of all the members of the enumeration.

and so you will be relying on implementation defined behavior if you use a value greater then the members define. In the case of signed integer overflow leads to undefined behavior as per section 5 which says:

If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.

Typically we see enums being assigned values outside of those specified by their members when they are used to represent bit fields.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • So if an implementation chose `unsigned char` as the underlying type representing `enum foobar`, attempting to set an `enum foobar` variable to `261U` would result in the variable being set to `BAR` (due to `unsigned` to `unsigned char` conversion)? – Vilhelm Gray Jul 10 '14 at 18:12
  • 1
    @VilhelmGray you would be subject to the conversion rules in `6.3.1.3` it would "rollover" in the unsigned char case. Signed overflow would invoke implementation defined behavior though. – Shafik Yaghmour Jul 10 '14 at 18:15
  • 2
    @ShafikYaghmour no undefined behavior because if the value cannot fit in the signed integer type C says the conversion is implementation-defined as per 6.3.1.3p3. – ouah Jul 10 '14 at 18:18
  • 1
    @ouah: Overflow on signed integer conversion yields an implementation-defined result *or* raises an implementation-defined signal. The latter could lead to undefined behavior. (I know of no compiler that actually does this.) – Keith Thompson Jul 10 '14 at 18:31
  • 2
    In this case, the maximum value of any enumerator is 5. The narrowest possible compatible integer type has an upper bound of at least 127. So assigning any value from -127 to +127 to an `enum foobar` object is well defined. – Keith Thompson Jul 10 '14 at 18:33
  • 1
    @KeithThompson How could an implementation-defined signal lead to undefined behavior? – Vilhelm Gray Jul 10 '14 at 18:33
  • 2
    @KeithThompson strictly speaking it is not UB (the compiler cannot stop the translation for example), even if I agree with Seebs from C Committee: *From the point of view of someone writing portable code, this definition comes out very close to "the behavior is undefined", because I cannot predict what value I'll get, or whether I'll even get a value.* – ouah Jul 10 '14 at 18:44
  • 1
    @VilhelmGray: C11 7.14p4: "The complete set of signals, their semantics, and their default handling is implementation-defined, ...". An implementation could provide a signal handler for whatever signal is raised by a signed integer overflow. The standard does not restrict the behavior of that handler. Relevant: http://stackoverflow.com/a/18923818/827263 – Keith Thompson Jul 10 '14 at 18:53
1
enum foobar{
    FOO = 1,
    BAR = 5
};

enum foobar baz = 5;

the baz declaration is equivalent to:

enum foobar baz = BAR;

as BAR is an int of value 5.

This declaration is also valid:

enum foobar qux = 42;

C says an enum type is an integer type sufficiently large to represent all its enum constants. If the enum type is not sufficiently large, the value is converted to the enum integer type as for every integer type as per the rules of integer conversion (c99, 6.3.1.3). This integer conversion can be implementation-defined (see 6.3.1.3p3).

ouah
  • 142,963
  • 15
  • 272
  • 331
  • I don't see where it says that an `enum` type is an integer type. It's not mentioned in the definition of *integer type* in C11 6.2.5 . In 6.7.2.2 it says the enum type is *compatible with* some integer type but not that it *is* an integer type. Perhaps it is just an oversight in the standard wording, because the list in 6.3.1.1 suggests that an enum was supposed to be an integer type. – M.M Jan 27 '16 at 09:21
  • From 6.7.2.2 we conclude it's an integer type as only an integer type can meet these criteria. This is also further emphasized in the (non-normative) footnote 128) for *"The choice of type is implementation-defined"* that says *"An implementation may delay the choice of which integer type until all enumeration constants have been seen."*. – ouah Jan 27 '16 at 12:54