Enumerations are integers, except when they're not - Embedded.com

Enumerations are integers, except when they’re not

I recently explained that although both C and C++ provide void * as the generic data pointer type, each language treats the type a little differently.1 For any object type T , both C and C++ let you implicitly convert an object of type T * to void * . (An implicit conversion is one that doesn't require a cast.) However, only C lets you implicitly convert in the opposite direction–from void * to T * .

There's a similar disparity in the way the two languages treat enumeration values. Both C and C++ let you implicitly convert an enumeration value into an int . However, only C lets you implicitly convert an int into an enumeration.

For example, consider these enumeration definitions:

enum day{    day_begin,    Sun = day_begin, Mon, Tue, ... , Sat,    day_end};typedef enum day day;enum month{    month_begin,    Jan = month_begin, Feb, Mar, ... , Dec,    month_end};typedef enum month month;   

The identifier appearing immediately after the keyword enum is a tag, not a type. I typically define a type name with the same spelling as each tag and then just use the type name.2 I often define additional _begin and _end enumeration constants to facilitate writing loops, like the one you'll see shortly.3

In C, each enumeration constant has type int and each enumeration type is compatible with some integer type. (The integer types include all three character types–plain, signed, and unsigned.) The choice of compatible type is implementation-defined. The C standard grants the freedom to use different integer types to represent different enumeration types, but most compilers just use int to represent all enumeration types.

Treating enumerations as just integers leads to some useful behaviors. For example, C lets you apply all the usual integer operations to enumerations, so you can easily write loops that iterate over a range of enumeration values, as in:

day d;for (d = day_begin; d != day_end; ++d)    ...   

Unfortunately, C also lets you do highly questionable things with enumerations such as:

day d;month m;d = Dec;        // assign a month to a daym = 31;         // assign an arbitrary int to a monthif (d < m)      // compare a day with a month    ...   

If you compile at the highest warning level, some C compilers may warn you about these operations, but most don't. If you program in C and want to prevent such questionable operations, you should use a static analyzer… or compile the code with C++.

In C++, each enumeration is a distinct type. For compatibility with C, C++ permits implicit conversions from enumeration types to int , but it draws the line there. C++ doesn't permit implicit conversions from integer types to enumeration types or from one enumeration type to another. Thus, statements such as:

d = Dec;        // assign a month to a daym = 31;         // assign an arbitrary int to a month   

are valid in C, but not in C++. A comparison between different enumerations, such as:

if (d < m)      // compare a day with a month    ...   

is valid in C++ (both enumeration values convert to int ), but may provoke a warning.

In prohibiting implicit conversions from int to any enumerations type, C++ also prohibits arithmetic on enumerations. Consequently, C++ will not compile a loop such as:

for (day d = day_begin; d != day_end; ++d)    ...   

unless you overload the ++ operator to increment a day .

The new C++ standard is planning to introduce an even more strongly-typed enumeration. An enum class defined as:

enum class day { ... };   

disallows implicit conversion from day to int . For example, if d is a day and m is a month and either day or month is an enum class, then this questionable comparison won't compile:

if (d < m)      // compare a day with a month    ...   

If you really want it to compile, you're going to have to overload the < operator to accept a day and a month . I hope you don't.

Enum classes have other nice properties which I hope to discuss in a future column.

Dan Saks is president of Saks & Associates, a C/C++ training and consulting company. For more information about Dan Saks, visit his website at www.dansaks.com. Dan also welcomes your feedback: e-mail him at . For more information about Dan .

Endnotes:

1. Saks, Dan. “Into, but not out of, the void,” Embedded.com, June 2008, www.embedded.com/208403407.

2. Saks, Dan. “Tag vs.Type Names,” Embedded Systems Programming , October 2002, p. 7.

3. Saks, Dan. “More on Enumerations,” Embedded Systems Programming , July 2003, p. 38.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.