假设我有一个32位的机器:
enum foo {
val1 = 0x7FFFFFFF, // originally '2^31 - 1'
val2,
val3 = 0xFFFFFFFF, // originally '2^32 - 1'
val4,
val5
};
val2、val4和val5的值是多少?我知道我可以测试它,但结果是否是标准化的?
假设我有一个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. 符合性
如果违反出现在约束或运行时约束之外的“应”或“不应”要求,则行为未定义。
uint_least64_t
不是必须存在吗?它不是一种 无符号整数类型 吗? - dypunsigned long long
来存储至少2^64-1(“的幂”,而不是“异或”),因此0xFF FF FF FF不应该是一个问题。 - dypvoid foo(enum sillyQuestion)
);但是枚举值并不具有该类型,它们被声明为 int
类型的常量。 - dyp根据C++11标准(§7.2,6,强调是我的):
如果枚举类型的底层类型未固定,则底层类型为能够表示该枚举类型中所有枚举值的整数类型。 如果没有任何整数类型能够表示所有枚举值,则该枚举类型无效。 底层类型的实际类型是由实现定义的,但底层类型不得大于int,除非枚举值的值无法适应int或unsigned int。
因此,如果有一个比32位更大的整数类型,编译器将会正确处理。如果没有,枚举类型将无效。值不会进行包装处理。
这些值将是:
enum foo {
val1 = 0x7FFFFFFF,
val2, // 0x80000000 = 2^31
val3 = 0xFFFFFFFF,
val4, //0x0000000100000000 = 2^32
val5 //0x0000000100000001 = 2^32+1
};
递增的数字也被明确定义了(§7.2,2):
[...]没有初始化器的枚举符定义会使该枚举符的值在上一个枚举符的值基础上递增一。
foo
,而不是在C中。 C++标准的§7.2,1清楚地说明:“枚举是具有命名常量的独特类型”。 - Arne Mertz5.2.4.2.1 规定 int
至少需要16位;据我所知,没有上限(但long
需要更长或相等,详见6.2.5 /8)。
6.5 /5:
如果在表达式求值期间出现异常情况(也就是说,如果结果在其类型的表示范围内不是数学上定义的),则行为未定义。
那么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
我认为这样可以缩小范围,例如将枚举类型的大小减少到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得到的常量表达式的值。[...]
因此,该示例会导致未定义行为:
enum foo {
val0 = INT_MAX,
val1 // equivalent to `val1 = INT_MAX+1`
};
int
可以窄至 16 位。 - Keith Thompsonval4
和val5
无法适应32位无符号整数,因此编译器必须使用比它更大的类型。 - Arne Mertz