Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enum constants behaving differently in C and C++

Tags:

c++

c

Why does this:

#include <stdio.h> #include <limits.h> #include <inttypes.h>  int main() {     enum en_e {         en_e_foo,         en_e_bar = UINT64_MAX,     };     enum en_e e = en_e_foo;     printf("%zu\n", sizeof en_e_foo);     printf("%zu\n", sizeof en_e_bar);     printf("%zu\n", sizeof e); } 

print 4 8 8 in C and 8 8 8 in C++ (on a platform with 4 byte ints)?

I was under the impression that the UINT64_MAX assignment would force all the enumerations constants to at least 64 bits, but en_e_foo remains at 32 in plain C.

What is the rationale for the discrepancy?

like image 407
PSkocik Avatar asked Jan 24 '17 18:01

PSkocik


People also ask

What is the difference between enum and constant in C?

Enums impose a specific type onto your constants: they will have type int (or, possibly, larger signed integer type), and they will always be signed. With macros you can use constant syntax, suffixes and/or explicit type conversions to produce a constant of any type.

Does C support enums?

Enumeration or Enum in C is a special kind of data type defined by the user. It consists of constant integrals or integers that are given names by a user. The use of enum in C to name the integer values makes the entire program easy to learn, understand, and maintain by the same or even different programmer.

What are enumeration variables How are they declared and advantages?

An enumeration type declaration gives the name of the (optional) enumeration tag. And, it defines the set of named integer identifiers (called the enumeration set, enumerator constants, enumerators, or members). A variable of the enumeration type stores one of the values of the enumeration set defined by that type.


2 Answers

In C, an enum constant is of type int. In C++, it's of the enumerated type.

enum en_e{     en_e_foo,     en_e_bar=UINT64_MAX, }; 

In C, this is a constraint violation, requiring a diagnostic (if UINT64_MAX exceeds INT_MAX, which it very probably does). A C compiler may reject the program altogether, or it may print a warning and then generate an executable whose behavior is undefined. (It's not 100% clear that a program that violates a constraint necessarily has undefined behavior, but in this case the standard doesn't say what the behavior is, so that's still undefined behavior.)

gcc 6.2 doesn't warn about this. clang does. This is a bug in gcc; it incorrectly inhibits some diagnostic messages when macros from standard headers are used. Thanks to Grzegorz Szpetkowski for locating the bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71613

In C++, each enumeration type has an underlying type, which is some integer type (not necessarily int). This underlying type must be able to represent all the constant values. So in this case, both en_e_foo and en_e_bar are of type en_e, which must be at least 64 bits wide, even if int is narrower.

like image 183
Keith Thompson Avatar answered Oct 02 '22 12:10

Keith Thompson


That code just isn't valid C in the first place.

Section 6.7.2.2 in both C99 and C11 says that:

Constraints:

The expression that defines the value of an enumeration constant shall be an integer constant expression that has a value representable as an int.

A compiler diagnostic is mandatory because it is a constraint violation, see 5.1.1.3:

A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined.

like image 36
Ben Voigt Avatar answered Oct 02 '22 10:10

Ben Voigt