在C语言中,枚举类型的大小是多少?

167

我正在创建一组枚举值,但我需要每个枚举值为64位宽。如果我没记错的话,枚举通常与int大小相同;但我记得在某个地方读到过(至少在GCC中)编译器可以使枚举任何宽度以容纳其值。那么,是否可能拥有一个64位宽度的枚举?


1
那么如果我理解得正确,2^32枚举对你来说不够用?还是存在对齐问题,为什么你需要将其从32位扩展到64位,我非常好奇。 - jokoon
2
@jokoon:老实说,我已经记不清了。我想我希望枚举包含比2^32-1更大的值。 - mipadi
一个用途是当你需要枚举和指针之间的联合时。 - Demi
3
在确定enum大小时一个重要的考虑因素实际上是内存使用。内存优化已经死了,还是所有人都认为编译器仍然是宇宙中心,并且它自动将所有东西变得快速和最优而不需要程序员付出任何努力?如果你只需要256个值或更少的enum,那么为什么需要使用比所需更大的数据类型呢?(数据模型不是借口。这些值通常很容易进行符号扩展,例如在寄存器中存储时。) - AMDG
@AMDG 枚举值不需要连续。在嵌入式系统中,通常使用常量和/或枚举来命名内存映射的I/O接口中的单个位。因此,希望像1<<311<<30这样的大枚举值之间有巨大间隔是完全合理的。 - undefined
7个回答

120
从当前的C标准(C99)中获取:http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf 6.7.2.2枚举说明符 [...] 约束 定义枚举常量值的表达式应该是一个整数常量表达式,其值可以表示为int。 [...] 每个枚举类型应与char、有符号整数类型或无符号整数类型兼容。类型的选择是实现定义的,但必须能够表示枚举的所有成员的值。
请注意,编译器并不总是遵循标准,但本质上:如果您的枚举除int以外的任何类型,那么您在深度“不受支持的行为”领域,这可能会在一两年后回来咬您。
更新:最新公开可用的C标准草案(C11):http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1570.pdf 包含相同的条款。因此,本答案对于C11仍然有效。

3
只有这些,我想以下内容是有效的:枚举 { LAST = INT_MAX,LAST1,LAST2 }; 因此,LAST2在int中无法表示,但没有定义它的表达式。 - Johannes Schaub - litb
4
在实际的PDF文档中,它定义道:"枚举列表中的标识符被声明为具有int类型的常量[...]"。我省略了这部分以使语言不太啰嗦。 - Michael Stum
3
注意:“a signed integer type, or an unsigned integer type”。这不一定是 intshortlong 也是整数类型,并且无论实现选择什么,所有值都必须适合(“shall be capable of representing the values of all the members of the enumeration”)。 - user824425
10
值得注意的是:枚举常量和枚举类型并不是同一回事。前者是枚举声明列表中的内容,而后者是实际的变量。因此,虽然枚举常量必须为“int”类型,但实际的枚举变量可以是其他类型。这是标准中公认的不一致之处。 - Lundin
5
为了澄清Lundin的观点:对于enum my_enum { my_value }my_value将具有类型int,但是enum my_enum可以具有实现定义的类型,该类型必须至少表示所有枚举值。因此,my_value可能会被截断转换为enum my_enum,但保证不会溢出。 - P O'Conbhui
显示剩余2条评论

111

enum只保证足够容纳int值,编译器可以根据定义的枚举常量自由选择实际使用的类型,因此如果可以表示您定义的值,它可能会选择更小的类型。如果需要枚举常量无法适应int类型,就需要使用特定于编译器的扩展来实现。


14
根据@MichaelStum的回答,你的第一句话应该是“枚举类型只能保证适合于int值”,这与你最后一句话似乎有冲突。请澄清一个限制条件,是枚举类型应该比int大还是比int小? - HaskellElephant
作为对二进制补码平台(这是现在所有系统吗?)的一种丑陋的实现敏感的黑客技巧,您可以通过确保枚举包含负值来强制使枚举与int一样大。虽然不推荐使用此技术。 - persiflage
7
这个回答似乎暗示枚举类型的大小与“int”类型一样大。参考了C99标准的Michael Stum的回答表明,枚举类型的大小可能只有一个“char”类型那么小。 - Frank Kusters
3
这个回答的第一句话是不正确的。 枚举 只保证足够大,能够容纳枚举中最大枚举值的数值。 - M.M
@M.M,他的意思是要保存最大的int值。这是正确的陈述。你的陈述实际上是不正确的。如果枚举器比int大,那么enum将无法保存最大的枚举器。我通过将我的64位枚举器截断为最大的int(在我的情况下是32位)来学习到了这一点。 - SO_fix_the_vote_sorting_bug
在标准 C 中,@jdk1.0 所有的枚举器都具有 int 类型。您所描述的行为是编译器特定的扩展。 - M.M

24

虽然之前的答案是正确的,但有些编译器有选项来打破标准并使用最小的类型来包含所有值。

例如,在GCC中(文档在GCC手册中),可以这样实现:

enum ord {
    FIRST = 1,
    SECOND,
    THIRD
} __attribute__ ((__packed__));
STATIC_ASSERT( sizeof(enum ord) == 1 )

15
据我所见,实际上这并不违反标准。正如Michael Stum的回答中所解释的那样,只要所有值都适合,标准允许编译器选择枚举的实际类型。 - sleske
2
我曾经使用过 macOS 的 C++ 编译器,它利用枚举类型值范围有限的特点将它们存储在更小的类型中。我不记得是 Metrowerks Codewarrior 还是 XCode。这符合 C++ 标准。通常情况下不能假设 sizeof(MyEnum) == sizeof(int)。 - persiflage

0

只需将枚举的最后一个值设置为足够大的值,使其成为您想要的枚举大小即可:

enum value{a=0,b,c,d,e,f,g,h,i,j,l,m,n,last=0xFFFFFFFFFFFFFFFF};

3
虽然这段代码可能能够回答问题,但是提供关于它如何以及/或者为什么解决了问题的额外背景信息可以提高答案的长期价值。 - leopal
1
这是错误的。使用gcc 8.4.0编译您的示例:sizeof(a)为4,sizeof(last)为8。 - Mateo de Mayo
2
typedef enum {a1=0,b1,c1,d1,f1,last1=0xFFFFFFFFFFFFFFFF} testing1; typedef enum {a2=0,b2,c2,d2,f2,last2=0xFFFFFFFF} testing2; 类型为testing1的变量大小为8,类型为testing2的变量大小为4。 - scirdan

-1
我们对enum变量的大小没有控制权。 它完全取决于实现,编译器提供了使用enum来存储整数名称的选项,所以enum遵循整数的大小。

-2
在C语言中,enum保证大小与int相同。有一个编译时选项(-fshort-enums)可以将其缩短(这主要适用于值不超过64K的情况)。没有编译时选项可以将其大小增加到64位。

不是简短,有时更短。 - rsaxvc

-11
考虑以下代码:
enum value{a,b,c,d,e,f,g,h,i,j,l,m,n};
value s;
cout << sizeof(s) << endl;

它将输出4。因此,无论enum包含多少个元素,其大小始终是固定的。


7
Michael Stum的回答是正确的。这与编译器有关。您可以使用IAR EWARM自行尝试。IAR EWARM显示您的示例为1。如果有多达255个项,它仍会显示为1。在添加第256个项目后,它会增加到2。 - desowin
16
问题并不涉及 C++。 - Michas
8
在写任何C或C++代码之前,需要注意的重要事情:仅仅因为它编译通过并不意味着它符合标准。仅仅因为你得到了特定的结果,并不意味着标准规定你总是会得到那个结果或其他用户运行你的代码时也会得到同样的结果。像这样的问题需要回答参考标准或至少给定编译器/ABI的实现定义规范。仅编译和运行程序,并在某一天看到一个结果,并没有传达任何关于这些问题的教训(以及很少关于其他任何事情)。 - underscore_d

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接