6.7.3.3 枚举说明符
TIP
C23 里的枚举比传统 C 更复杂,因为它区分了“未固定底层类型的枚举”和“固定底层类型的枚举”。这两类枚举在完整性、兼容性和枚举成员类型上都不完全一样。
语法
枚举说明符支持三类形式:
- 直接给出枚举项列表的定义;
- 带可选固定底层类型的定义;
- 仅引用已有枚举类型的形式。
枚举项可以写成:
- 只有名字;
- 名字后跟属性;
- 名字后跟
= constant-expression。
固定底层类型写在
: specifier-qualifier-list中。
底层类型
所有枚举都有底层类型。
若显式写出
enum-type-specifier,该枚举就有固定底层类型。若未显式写出,则底层类型等于该枚举的兼容类型;它可能是:
char- 某个标准有符号整数类型
- 某个标准无符号整数类型
- 或扩展整数类型
约束
对固定底层类型枚举,枚举常量的值必须能表示在该底层类型中。
如果固定底层类型枚举里,某个未显式赋值的枚举项依靠“前一个值加一”得到新值,那么前一个枚举项不能已经是底层类型最大值。
对未固定底层类型枚举,显式赋值表达式必须是整数常量表达式。
对未固定底层类型枚举,所有枚举项值必须存在某种
char、标准/扩展有符号整数类型或无符号整数类型能够全部表示。若出现
enum-type-specifier,它必须命名某种整数类型,且该类型:- 不能是枚举类型;
- 不能是位精确整数类型。
固定底层类型枚举只能用带
enum-type-specifier的方式定义。未固定底层类型枚举的说明符中不得出现
enum-type-specifier。
语义
写在
enum说明符上的属性附着到该枚举类型本身。写在枚举项后的属性附着到该枚举项。
第一个未显式赋值的枚举项,值为
0。之后未显式赋值的枚举项,值等于前一个枚举项的值再加
1。显式赋值可以导致多个枚举项拥有相同的值。
枚举项在当前作用域中被声明为常量。
枚举成员类型
标准专门区分了:
- 枚举类型本身;
- 枚举成员类型。
对固定底层类型枚举:
- 枚举成员类型就是该枚举类型;
- 枚举类型与其底层类型兼容;
- 经左值转换后,它在提升、转换和算术行为上,与底层类型一致。
对未固定底层类型枚举:
- 在枚举完成前,处理各枚举项时,枚举项类型可能临时取
int、显式表达式类型,或者“前一个值加一”后的类型; - 枚举完成后,若所有值都能由
int表示,则枚举成员类型是int; - 否则,枚举成员类型是该枚举类型本身。
- 在枚举完成前,处理各枚举项时,枚举项类型可能临时取
未固定底层类型枚举的兼容类型由实现决定,但必须足以表示所有枚举成员值。
重声明
同一枚举类型中的枚举常量可以在同一作用域内用相同值重新声明。
若两个带
enum-type-specifier的枚举说明符声明的是同一类型,则它们的底层类型必须兼容。
读者应特别注意的区别
enum E { A };与enum E : unsigned char { A };在可移植性上差别很大。前者的兼容类型是实现定义的;后者的行为则直接锚定到
unsigned char。固定底层类型枚举在其
enum类型说明符结束后立刻完整。未固定底层类型枚举则要等到枚举项列表闭合后才完整。