C++ 大枚举值的表示是否有任何保证?
假设我有(在32位机器上) val2、val4和val5的值是多少?我知道我可以测试它,但是结果标准化了吗?在C标准中: C11(n1570),§6.7.2.2枚举说明符 每个枚举类型应与C++ 大枚举值的表示是否有任何保证?,c++,c,enums,C++,C,Enums,假设我有(在32位机器上) val2、val4和val5的值是多少?我知道我可以测试它,但是结果标准化了吗?在C标准中: C11(n1570),§6.7.2.2枚举说明符 每个枚举类型应与char、有符号整数类型或无符号整数类型兼容。类型选择由实现定义,但应能够表示枚举的所有成员的值 如果编译器使用的基础类型不能表示这些值,则行为未定义 C11(n1570),§4。一致性 如果违反了出现在约束或运行时约束之外的“应”或“不应”要求,则行为未定义 这里是C++答案:7.2/6,它表示: […]基础
char
、有符号整数类型或无符号整数类型兼容。类型选择由实现定义,但应能够表示枚举的所有成员的值
如果编译器使用的基础类型不能表示这些值,则行为未定义
C11(n1570),§4。一致性
如果违反了出现在约束或运行时约束之外的“应”或“不应”要求,则行为未定义
这里是C++答案:7.2/6,它表示:
[…]基础类型是可以表示所有 枚举中定义的枚举数值。如果没有整数类型 可以表示所有枚举数值,枚举为 格式不正确。使用哪种积分类型由实现定义 作为基础类型,但基础类型不得为 大于int,除非枚举数的值不能容纳int 或无符号整数 因此,与C相比:如果编译器找不到类型,则没有未定义的行为,并且编译器不能仅将其512位扩展整数类型用于双值枚举 这意味着,在您的示例中,基础类型可能是一些有符号的64位类型-大多数编译器总是先尝试类型的有符号版本。来自C++11标准(§7.2,6,emphasis mine): 对于基础类型不固定的枚举,基础类型是一个整数类型,可以表示枚举中定义的所有枚举数值。如果没有整数类型可以表示所有枚举数值,则枚举的格式不正确。实现定义了使用哪种整数类型作为基础类型,但基础类型不得大于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
和
可在任何允许的地方出现
注意,枚举类型与枚举数/枚举常量类型之间存在差异:
在我看来,这允许缩小范围,例如将枚举类型的大小减少到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`
};
充其量,这将是实现定义,枚举的大小没有上限。只是为了笑,这两个表达式都会编译,并且产生非常小的数字。@ Dyp,不,它是XOR运算符之前-OP用它来说明“两个幂”。@ Bathsheba:C和C++是不同的语言;“你想要哪一个?”芭丝谢芭:我看到你把它都贴上了标签。这就是我的观点:它们之间的答案是不同的。但是,
uint\u至少64\u t
不是必须存在的吗?它不是无符号整数类型吗?@Dyp,是的,所以编译器可以选择它。但是,如果您执行0xFFFFFFFFFFFFFFFFLU
,那么如果编译器不支持大于64位的整数,这将是未定义的行为。此外,无符号long long
需要能够存储至少2^64-1(“到的幂”,而不是“XOR”),因此0xFF应该不会是一个问题。我可能错了,但我认为更相关的是C要求枚举数的类型为int
(严格地说),6.7.2。2@DyP你有报价吗?上面的引文只需要一个“整数类型”,它可能很长,uint\u至少64\u t
或其他。val4
和val5
不适合32位无符号int,所以编译器必须使用比它大的类型。好吧,忘了这些。@SebastianRedl:你确定有符号吗?我认为GCC和Clang最好使用未签名的对应项(除非有一个负值)。检查CLAN代码,它似乎更喜欢C++和带签名类型的C++的无符号类型。我敢打赌GCC也是这样做的——comp
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
enum foo {
val0 = INT_MAX,
val1 // equivalent to `val1 = INT_MAX+1`
};