12

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

编译器是否像对待 aenum一样对待 a union

4

6 回答 6

20

在 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,onetwo的大小都是 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 说:

错误:枚举值溢出

于 2013-07-26T18:34:11.537 回答
9

枚举不是一种结构,它只是为一组整数命名的一种方式。这种类型的变量的大小就是底层整数类型的大小。这将是在枚举中保存最大值所需的类型。因此,只要所有类型都适合同一个整数类型,大小就不会改变。

于 2013-07-26T18:22:25.007 回答
8

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

从 C99 §6.7.2.2/4 开始:

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

从 C++03 §7.2/5 开始:

枚举的底层类型是一个整数类型,可以表示枚举中定义的所有枚举值。使用哪种整数类型作为枚举的基础类型是实现定义的,除非基础类型不得大于,int除非枚举数的值不能放入intorunsigned int中。如果enumerator-list为空,则基础类型就好像该枚举具有一个值为 0 的单个枚举器。sizeof()应用于枚举类型、枚举类型的对象或枚举器的值是sizeof()应用于基础类型。

于 2013-07-26T18:21:57.583 回答
3

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

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

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

于 2013-07-30T08:02:47.953 回答
1

an 的大小enum是“一个至少足够大以包含声明中指定的任何值的整数类型”。许多编译器只会使用 a int(可能是unsigned),但有些编译器会使用charor 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,
  ...
};

它有助于避免错误地分配重复值,并且您甚至无需关心特定值是什么(除非您真的需要)。

于 2013-07-26T18:27:07.933 回答
0

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

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

于 2013-07-26T19:29:35.233 回答