*Updated the post inspired by Nemo's great comments.
enum MY_ENUM{ MY_OK = 0, MY_NOT_OK }; void foo() { int i = -1; enum My_ENUM my_enum = MY_OK; if( i < my_enum) printf("I am OK!\n"); else printf("I am NOT OK!\n"); }
For the above example, we will see "I am NOT OK!". Why, the reason is in this example my_enum is regarded as unsigned int. Therefore, it will be converted into unsigned before the comparison. After the conversion, it will always be non-negative so the if will take the else branch. But what about this code snippet (just a little bit modification):
enum MY_ENUM{ MY_OK = 0, MY_NOT_OK }; void foo() { int i = -1; enum My_ENUM my_enum = MY_OK; if( i < MY_OK) printf("I am OK!\n"); else printf("I am NOT OK!\n"); }
It will print "I am OK!" instead. The reason is in this example MY_OK is regarded as int.
Why we will see results like this? It is kind of confusing. To find out the things under-hood, we need to look at the C standard. There are several sections related to our problem.
- Section 6.4.4.3 says enumerators have type int.
- Section 6.7.2.2/4 states that the enumeration type has a compatible type capable of representing the values of all enumerator members.
- Section 6.7.2.2/2 suggests that an enumerator initialized with a constant expressionthat falls outside the range of an int has unspecified or undefined behavior.
Then what if you want enumeration type to be int? Just follow Section 6.7.2.2/4 and have the enumeration defined as follow:
since we only need to represent -1,0 and 1 here, the enumeration type needs to be int.
We should be careful about Section 6.7.2.2/2. Since it suggests if we define something as follow, the behavior will be unspecified.
enum MY_ENUM{ MY_NEG = -1 MY_OK = 0, MY_NOT_OK };
since we only need to represent -1,0 and 1 here, the enumeration type needs to be int.
We should be careful about Section 6.7.2.2/2. Since it suggests if we define something as follow, the behavior will be unspecified.
enum MY_ENUM{ MY_NEG = -1 MY_OK = 0, MY_BIG = 0x80000000 };0x80000000 can't be represented in a 32bit int. Though in gcc, the enumeration type is still int here, we cannot expect a uniform behavior on other compilers.
The type of an enumeration is "implementation-defined"; on a different compiler, it might be signed (see http://stackoverflow.com/questions/159034/). So your first example will behave differently on different platforms.
ReplyDeleteThe type of an enumeration constant is always "int" (C standard section 6.4.4.3), so your second example will behave the same on all platforms.
If you want to force your enum to be signed, you can do this:
enum MY_ENUM {
MY_ENUM_FORCE_SIGNED=-1,
MY_OK,
MY_NOT_OK
};
By the way, the comma after the last element in your enum is technically a syntax error. GCC will inform you of this if you specify "-pedantic".
Thanks for your great comments, Nemo. I also did some further investigation and updated the original posts. There are also Section 6.7.2.2/4 and 6.7.2.2/2 related to enum.
Delete