为什么enum
总是 2 或 4 字节的大小(分别在 16 位或 32 位架构上),而不管类型中的枚举数是多少?
编译器是否像对待 aenum
一样对待 a union
?
在 C 和 C++ 中,enum
类型的大小是实现定义的,并且与某些整数类型的大小相同。
一种常见的方法是使所有enum
类型的大小与 相同int
,因为这通常是最有效访问的类型。例如,将其设为单个字节将节省非常少量的空间,但可能需要更大更慢的代码来访问它,具体取决于 CPU 架构。
在 C 中,枚举常量由 type 定义int
。所以给出:
enum foo { zero, one, two };
enum foo obj;
表达式zero
是类型的int
,但是obj
是类型的enum foo
,它的大小可能与 . 相同,也可能不同int
。鉴于常量是 type int
,使枚举类型具有相同大小往往更容易。
在 C++ 中,规则是不同的;常量是枚举类型。但同样,出于效率原因,将每种类型作为一个“单词”通常是最有意义的enum
,通常是 的大小。int
并且 2011 ISO C++ 标准增加了为类型指定底层整数类型的能力enum
。例如,您现在可以编写:
enum foo: unsigned char { zero, one, two };
这保证了类型foo
和常量zero
,one
和two
的大小都是 1 字节。C 没有此功能,并且旧的 2011 之前的 C++ 编译器不支持它(除非它们将其作为语言扩展提供)。
(以下是题外话。)
那么,如果您的枚举常数太大而无法放入 中int
怎么办?您不需要 2 31甚至 2 15不同的常量来执行此操作:
#include <limits.h>
enum huge { big = INT_MAX, bigger };
的值为 ,big
通常INT_MAX
为 2 31 -1,但可以小至 2 15 -1 (32767)。的值bigger
是隐含的big + 1
。
在 C++ 中,这是可以的;编译器将简单地选择一个huge
足够大的底层类型来保存 value 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
除非枚举数的值不能放入int
orunsigned int
中。如果enumerator-list为空,则基础类型就好像该枚举具有一个值为 0 的单个枚举器。sizeof()
应用于枚举类型、枚举类型的对象或枚举器的值是sizeof()
应用于基础类型。
在我看来,OP 已经假定枚举是某种存储其中声明的值的集合。这是不正确的。
C/C++ 中的枚举只是一个具有严格定义值范围的数值变量。枚举的名称是数字的一种别名。
存储大小不受枚举值数量的影响。存储大小是实现定义的,但主要是sizeof(int)
.
an 的大小enum
是“一个至少足够大以包含声明中指定的任何值的整数类型”。许多编译器只会使用 a int
(可能是unsigned
),但有些编译器会使用char
or short
,这取决于优化或其他因素。具有enum
少于 128 个可能值的 a 将适合 a char
(256 for unsigned char
),并且您必须有 32768 (或 65536) 个值才能溢出 a ,并且在大多数现代系统上short
超过 2 或 40 亿个值才能超出 a 。int
Anenum
本质上只是定义一堆不同常量的更好方法。而不是这个:
#define FIRST 0
#define SECOND 1
...
你刚才:
enum myenum
{ FIRST,
SECOND,
...
};
它有助于避免错误地分配重复值,并且您甚至无需关心特定值是什么(除非您真的需要)。
使enum
类型更小而不是int
更小的类型可以适合所有值的大问题是,它会使翻译单元的 ABI 依赖于枚举常量的数量。例如,假设您有一个库使用enum
具有 256 个常量的类型作为其公共接口的一部分,并且编译器选择将该类型表示为单个字节。现在假设您向库中添加了一个新功能,现在需要 257 个常量。编译器必须切换到新的大小/表示,现在为旧接口编译的所有目标文件都将与您更新的库不兼容;您必须重新编译所有内容才能使其再次工作。
因此,任何理智的实现总是使用int
类型enum
。