是否对大型枚举值的表示有任何保证?
Are there any guarantees on the representation of large enum values?
假设我有(在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位类型—大多数编译器总是首先尝试类型的带符号版本。
- 表示"accepting anything for this template argument" C++概念的通配符
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 如何将ampl中的集合表示为c++中的向量
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- std::is_base_of表示ctor编译错误
- 如何在不产生任何垃圾的情况下获得C中的像素
- C++ 表示 NIC 收到数据时没有收到任何内容
- 整数文本太大,无法用任何整数类型表示--C++
- 任何表示具有有序元素的对的 stl/boost 类型
- 将使用预处理器指令来定义美元符号表示的内容会导致任何冲突
- 任何表示函数参数的方式
- CMake表示,它已经编写了构建文件,但没有找到任何构建文件
- C++标准是否指定了浮点数字表示的任何内容
- 是否对大型枚举值的表示有任何保证?
- 我如何计算需要多少位来表示任何负值
- 是否有任何关于布尔值的二进制表示的保证
- GCC 或 Clang '-std=' 是否有任何"moving target"别名值,表示"use the latest standard"?
- 在C++中不表示任何内容
- 接受std::chrono::任何表示/周期的持续时间
- 将keycode的字符串表示形式转换为Qt::Key(或任何int)并返回