枚举值的常量枚举大小,无论枚举值的数量

为什么enum的大小总是2或4个字节(分别在16位或32位架构上),而不管类型中的枚举数是多少?

编译器是否将enum视为union

在C和C ++中, enum类型的大小是实现定义的,并且与某个整数类型的大小相同。

一种常见的方法是使所有enum类型与int大小相同,这仅仅是因为它通常是实现最有效访问的类型。 例如,将其设为单个字节可以节省非常小的空间,但可能需要更大更慢的代码来访问它,具体取决于CPU架构。

在C中,枚举常量int类型的定义。 所以给出:

 enum foo { zero, one, two }; enum foo obj; 

表达式zero的类型为int ,但obj的类型为enum foo ,其大小可能与int相同,也可能不同。 鉴于常量是int类型,它往往更容易使枚举类型具有相同的大小。

在C ++中,规则是不同的; 常量是枚举类型。 但同样,出于效率原因,每个enum类型通常最有意义的是一个“单词”,通常是int的大小。

2011 ISO C ++标准添加了为enum类型指定基础整数类型的function。 例如,您现在可以写:

 enum foo: unsigned char { zero, one, two }; 

这保证了类型foo和常量zerotwo的大小都是1字节。 C没有此function,并且2011年以前的C ++编译器不支持它(除非它们将其作为语言扩展提供)。

(接下来是。)

那么如果你的枚举常量太大而不适合int呢? 你不需要2 31 ,甚至2 15 ,不同的常量来做到这一点:

 #include  enum huge { big = INT_MAX, bigger }; 

big的值是INT_MAX ,通常为2 31 -1,但可以小到2 15 -1(32767)。 bigger的值隐含big + 1

在C ++中,这没关系; 编译器只需选择一个足够大的底层类型来保存值INT_MAX + 1 。 (假设存在这样的类型;如果int是64位并且没有大于那的整数类型,那将是不可能的。)

在C中,由于枚举常量的类型为int ,因此上述内容无效。 它违反了N1570 6.7.2.2p2中规定的约束:

定义枚举常量值的表达式应为整数常量表达式,其值可表示为int

所以编译器必须拒绝它,或至少警告它。 例如,gcc说:

错误:枚举值溢出

枚举不是结构,它只是给一组整数赋予名称的一种方式。 具有此类型的变量的大小只是基础整数类型的大小。

枚举的大小是实现定义的 – 允许编译器选择它想要的任何大小,只要它足够大以适合所有值。 一些编译器选择对所有枚举类型使用4字节枚举,而一些编译器将选择适合枚举值的最小类型(例如,1,2或4个字节)。 C和C ++语言标准允许这两种行为。

从C99§6.7.2.2/ 4:

每个枚举类型应与char ,有符号整数类型或无符号整数类型兼容。 类型的选择是实现定义的, 110)但应能够表示枚举的所有成员的值。

来自C ++03§7.2/ 5:

枚举的基础类型是一个整数类型,可以表示枚举中定义的所有枚举器值。 它是实现定义的,其中整数类型用作枚举的基础类型,除了基础类型不应大于int除非枚举器的值不能适合intunsigned int 。 如果枚举器列表为空,则基础类型就好像枚举具有值为0的单个枚举器。应用于枚举类型,枚举类型的对象或枚举器的sizeof()的值是sizeof()应用于基础类型。

在我看来,OP已经假定枚举是某种集合,它存储在其中声明的值。 这是不正确的。

C / C ++中的枚举只是一个具有严格定义的值范围的数字变量。 枚举的名称是数字的别名。

存储大小不受枚举值的数量的影响。 存储大小是实现定义的,但大多数是sizeof(int)

enum的大小是“一个至少足以包含声明中指定的任何值的整数类型”。 许多编译器只使用int (可能是unsigned ),但有些将使用charshort ,具体取决于优化或其他因素。 一个少于128个可能值的enum将适合一个char (256表示unsigned char ),并且你必须有32768(或65536)个值来溢出一个short ,并且需要2或40亿个值才能在大多数情况下超过int现代系统。

enum基本上只是定义一堆不同常量的更好方法。 而不是这个:

 #define FIRST 0 #define SECOND 1 ... 

你刚才:

 enum myenum { FIRST, SECOND, ... }; 

它有助于避免错误地分配重复值,并且无需关心特定值(除非您确实需要)。

当较小的类型适合所有值时,使enum类型小于int的大问题是它会使转换单元的ABI依赖于枚举常量的数量。 例如,假设您有一个库,该库使用具有256个常量的enum类型作为其公共接口的一部分,并且编译器选择将该类型表示为单个字节。 现在假设您向库中添加了一个新function,现在需要257个常量。 编译器必须切换到新的大小/表示,现在为旧接口编译的所有目标文件都与更新的库不兼容; 你将不得不重新编译一切,使其再次工作。

因此,任何理智的实现总是使用int作为enum类型。