是否对大型枚举值的表示有任何保证?

Are there any guarantees on the representation of large enum values?

本文关键字:任何保 表示 大型 枚举 是否      更新时间:2023-10-16

假设我有(在32位机器上)

enum foo {
    val1 = 0x7FFFFFFF, // originally '2^31 - 1'
    val2,
    val3 = 0xFFFFFFFF, // originally '2^32 - 1'
    val4,
    val5
};

val2, val4和val5的值是多少?我知道我可以测试它,但是结果是标准化的吗?

C语言标准:

C11 (n1570),§6.7.2.2枚举说明符

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

如果编译器使用的底层类型不能表示这些值,则行为是未定义的。

C11 (n1570),§4。一致性

如果违反了约束或运行时约束之外出现的"应该"或"不应该"要求,则该行为是未定义的。

从c++ 11标准(§7.2,6 ,我特别强调):

对于基础类型不固定的枚举,基础类型为整型,可以表示枚举中定义的所有枚举数值。如果没有整数类型可以表示所有枚举数值,则该枚举是病态的。将整型用作基础类型是由实现定义的,除非枚举数的值不能装入int型或无符号int型,否则基础类型不能大于int型。

因此,如果存在大于32位的整型,编译器将高兴地做正确的事情。如果不是,则枚举为非格式。没有包装。

值将是:

enum foo {
    val1 =                       0x7FFFFFFF, 
    val2,              //        0x80000000   = 2^31
    val3 =                       0xFFFFFFFF, 
    val4,              //0x0000000100000000   = 2^32
    val5               //0x0000000100000001   = 2^32+1
};

递增数也有很好的定义(§7.2,2):

[…没有初始化式的枚举数定义将前一个枚举数的值加1后得到的值赋给该枚举数。

C99/C11

前奏:

5.2.4.2.1要求int宽度至少为 16位;我想没有上限(long必须更长或等于6.2.5/8)。

6.5/5:

如果在表达式求值期间出现异常条件(即,如果结果没有在数学上定义,或者不在其类型的可表示值范围内),则行为未定义。


如果你的' int '是32位宽(或更小)

则OP中的示例违反了6.7.2.2/2:

约束

定义枚举常量值的表达式必须是整数具有可表示为int的值的常量表达式。

此外,枚举数定义为类型为int的常量,6.7.2.2/3:

枚举器列表中的标识符声明为类型为int和的常量可在允许的地方出现。


注意,枚举的类型与枚举数/枚举常量: 的类型是有区别的。
enum foo { val0 };
enum foo myVariable;        // myVariable has the type of the enumeration
uint_least8_t v = val0*'c'; // if val0 appears in any expression, it has type int


在我看来,这允许窄化,例如将enum 类型的大小减少到8位:

enum foo { val1 = 1, val2 = 5 };
enum foo myVariable = val1;    // allowed to be 8-bit

但是似乎不允许扩展,例如

enum foo { val1 = INT_MAX+1 }; // constraint violation AND undefined behaviour
// not sure about the following, we're already in UB-land
enum foo myVariable = val1;    // maximum value of an enumerator still is INT_MAX
                               // therefore myVariable will have sizeof int

枚举数的自增

因为6.7.2.2/3,

[…没有=的后续枚举数将其枚举常量定义为上一个枚举常量的值加上1后得到的常量表达式的值。[…]

示例结果为UB:

enum foo {
    val0 = INT_MAX,
    val1            // equivalent to `val1 = INT_MAX+1`
};

这是c++的答案:在7.2/6中,它说:

[…底层类型是一个可以表示所有的整型枚举中定义的枚举数值。如果没有整型能代表所有枚举数的值,枚举数是不规范的。使用哪种整型由实现定义作为基础类型,但基础类型不得为大于int型,除非枚举数的值不能装入int型或unsigned int.

与C相比:如果编译器找不到类型,则没有未定义行为,并且编译器不能仅为双值enum使用其512位扩展整数类型。

这意味着在您的示例中,底层类型可能是某种带符号的64位类型—大多数编译器总是首先尝试类型的带符号版本。