假设我(在32位机器上)
enum foo {
val1 = 0x7FFFFFFF, // originally '2^31 - 1'
val2,
val3 = 0xFFFFFFFF, // originally '2^32 - 1'
val4,
val5
};
val2,val4和val5的值是多少?我知道我可以测试它,但结果标准化?
答案 0 :(得分:16)
在C标准中:
C11(n1570),§6.7.2.2枚举说明符
每个枚举类型应与
char
,有符号整数类型或无符号整数类型兼容。类型的选择是实现定义的,但应能够表示枚举的所有成员的值。
如果编译器使用的基础类型无法表示这些值,则行为未定义。
C11(n1570),§4。一致性
如果违反约束或运行时约束之外的''shall''或''shall not''要求,则行为未定义。
答案 1 :(得分:10)
从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):
[...]没有初始化器的枚举器定义为枚举器提供了通过将前一个枚举器的值增加一个而获得的值。
答案 2 :(得分:4)
5.2.4.2.1 要求int
至少 16位宽; AFAIK没有上限(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 加到前一个枚举常量的值而获得的常量表达式的值。 [...]
UB中的示例结果:
enum foo {
val0 = INT_MAX,
val1 // equivalent to `val1 = INT_MAX+1`
};
答案 3 :(得分:2)
这里是C ++的回答:在7.2 / 6中,它声明:
[...]基础类型是一个可以代表所有类型的整数类型 枚举中定义的枚举器值。如果没有整数类型 可以表示所有枚举器值,枚举是 病态的。它是实现定义的,使用整数类型 作为基础类型,但基础类型不应该 大于int,除非枚举器的值不适合int 或unsigned int。
因此与C相比:如果编译器无法找到类型,则没有未定义的行为,并且编译器不能仅使用其512位扩展整数类型来实现双值枚举。
这意味着在您的示例中,基础类型可能是一些带符号的64位类型 - 大多数编译器总是先尝试签名版本的类型。