枚举常量在C和C ++中performance不同

为什么这样做:

#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); } 

在C中打印4 8 8 ,在C ++中打印8 8 8 (在具有4字节整数的平台上)?

我的印象是, UINT64_MAX赋值将强制所有的枚举常量至less为64位,但是en_e_foo在普通的C中保持在32位。

这种差异的基本原理是什么?

在C中, enum常量是inttypes的。 在C ++中,它是枚举types。

 enum en_e{ en_e_foo, en_e_bar=UINT64_MAX, }; 

在C中,这是违反约束的 ,需要诊断( 如果 UINT64_MAX超过INT_MAX ,它很可能INT_MAX )。 AC编译器可能完全拒绝该程序,或者可能会打印一个警告,然后生成一个行为未定义的可执行文件。 (一个违反约束的程序必然有不确定的行为,但是在这种情况下,标准没有说明行为是什么,所以这仍然是未定义的行为。

海湾合作委员会6.2并不警告这一点。 铛呢。 这是gcc中的一个bug。 当使用标准头文件的macros时,它会错误地禁止某些诊断消息。 感谢Grzegorz Szpetkowski查找错误报告: https ://gcc.gnu.org/bugzilla/show_bug.cgi?id = 71613

在C ++中,每个枚举types都有一个基础types ,它是一些整数types(不一定是int )。 这个基础types必须能够表示所有的常量值。 所以在这种情况下, en_e_fooen_e_bar都是en_e_bartypes,即使int较窄,它也必须至less为64位。

那个代码首先是无效的。

C99和C11的6.7.2.2节都说:

约束:

定义枚举常量值的expression式应该是一个整型常量expression式,其值可以表示为int

编译器诊断是强制性的,因为它违反了约束条件,请参见5.1.1.3:

如果预处理翻译单元或翻译单元包含违反任何语法规则或约束的情况,即使该行为也被明确指定为未定义或实现定义的,则一致性实现应产生至less一个诊断消息(以实现定义的方式标识)定义。

C中 ,虽然enum被认为是一个单独的types,枚举器本身总是有inttypes的。

C11 – 6.7.2.2枚举说明符

3枚举数列表中的标识符被声明为具有typesint的常量…

因此,你看到的行为是一个编译器扩展。

如果价值太大,只能扩大其中一个统计员的规模才有意义。


另一方面,在C ++中,所有枚举符都有它们声明的enumtypes。

因此,每个统计员的大小必须相同。 所以,整个enum大小扩大到存储最大的枚举。

正如其他人所指出的那样,由于违反约束,代码格式不正确(C)。

有GCC错误#71613 (2016年6月报告),其中指出,一些有用的警告是用macros沉默。

当使用来自系统头文件的macros时,有用的警告似乎被消除了。 例如,在下面的例子中,警告对两个枚举都是有用的,但只显示一个警告。 其他警告也可能发生同样的情况。

当前的解决方法可能是用一元+运算符预先安装macros:

 enum en_e { en_e_foo, en_e_bar = +UINT64_MAX, }; 

这使我的机器与GCC 4.9.2产生编译错误:

 $ gcc -std=c11 -pedantic-errors -Wall main.c main.c: In function 'main': main.c:9:20: error: ISO C restricts enumerator values to range of 'int' [-Wpedantic] en_e_bar = +UINT64_MAX 

C11-6.7.2.2 / 2

定义枚举常量值的expression式应该是一个整数常量expression式,其值可以表示为int

en_e_bar=UINT64_MAX是一个违反约束,这使得上述代码无效。 诊断信息应通过确认C11草案中规定的实施来产生:

如果预处理翻译单元或翻译单元包含违反任何语法规则或约束的情况,则符合的实现应产生至less一个诊断消息(以实现定义的方式标识)

看来海湾合作委员会有一些错误,并没有产生诊断信息。 (在Grzegorz Szpetkowski的回答中指出了Bug

我看了一下标准,由于6.7.2.2p2的原因,我的程序在C中似乎违反了约束条件:

约束:定义枚举常量值的expression式应该是一个整型常量expression式,其值可以表示为int。

并在C ++中定义为7.2.5:

如果基础types不固定,每个枚举器的types就是其初始化值的types: – 如果为枚举器指定了初始化器,则初始化值与expression式的types相同,常量expression式应该是整数常数expression式(5.19)。 – 如果没有为第一个枚举器指定初始化器,则初始化值具有未指定的整数types。 – 否则,初始化值的types与前一个枚举器的初始化值的types相同,除非递增的值不能在该types中表示,在这种情况下,types是一个未指定的整数types,足以包含递增的值。 如果不存在这样的types,则该程序是不合格的。