C++ 如果将无效值强制转换为枚举类,会发生什么情况?
考虑以下C++11代码:C++ 如果将无效值强制转换为枚举类,会发生什么情况?,c++,c++11,C++,C++11,考虑以下C++11代码: enum class Color : char { red = 0x1, yellow = 0x2 } // ... char *data = ReadFile(); Color color = static_cast<Color>(data[0]); 《标准》是否保证违约会发生?如果不是,在这里检查错误的正确、最有效、最优雅的方法是什么 编辑: 作为奖励,标准是否对此做出了任何保证,但使用了普通枚举 根据标准设置的颜色是什么 引用C++11和C++14标
enum class Color : char { red = 0x1, yellow = 0x2 }
// ...
char *data = ReadFile();
Color color = static_cast<Color>(data[0]);
《标准》是否保证违约会发生?如果不是,在这里检查错误的正确、最有效、最优雅的方法是什么
编辑:
作为奖励,标准是否对此做出了任何保证,但使用了普通枚举
根据标准设置的颜色是什么
引用C++11和C++14标准:
[expr.static.cast]/10
整型或枚举类型的值可以显式转换为枚举类型。如果原始值在枚举值(7.2)的范围内,则该值不变。否则,结果值未指定(并且可能不在该范围内)
让我们查找枚举值的范围:[dcl.enum]/7
对于基础类型为固定的枚举,枚举的值是基础类型的值
在CWG1766之前(C++11,C++14)
因此,对于数据[0]==100
,指定结果值(*),不涉及任何内容。更一般地说,当您从基础类型转换为枚举类型时,数据[0]
中的任何值都不会导致静态转换的UB
在CWG1766(C++17)之后
看见
[expr.static.cast]p10段落已得到加强,因此如果将枚举的可表示范围之外的值强制转换为枚举类型,则现在可以调用UB。这仍然不适用于问题中的场景,因为data[0]
是枚举的基础类型(见上文)
请注意,CWG1766被认为是标准中的一个缺陷,因此编译器实现者可以将其应用于C++11和C++14编译模式
(*)char
要求至少为8位宽,但不要求无符号
。根据C99标准附录E,要求可存储的最大值至少为127
与[expr]/4相比
如果在表达式求值期间,结果未在数学上定义或不在其类型的可表示值范围内,则行为未定义
在CWG1766之前,转换整数类型->枚举类型可以生成未指定的值。问题是:未指定的值是否可以超出其类型的可表示值?我相信答案是否定的——如果答案是肯定的,那么“此操作生成未指定的值”和“此操作具有未定义的行为”之间对有符号类型上的操作的保证不会有任何区别
因此,在CWG1766之前,即使static_cast(10000)
也不会调用UB;但在CWG1766之后,它确实调用了UB
现在,开关
语句:
[stmt.开关]/2
条件应为整型、枚举型或类型。[…]执行整体促销。
[conv.prom]/4
基础类型为固定(7.2)的非范围枚举类型的PR值可以转换为其基础类型的PR值。此外,如果可以对其基础类型应用整型提升,则基础类型为固定的非范围枚举类型的prvalue也可以转换为提升的基础类型的prvalue
注意:没有枚举基的作用域枚举的基础类型是int
。对于非范围枚举,基础类型由实现定义,但如果int
可以包含所有枚举数的值,则基础类型不得大于int
对于非范围枚举,这将导致/1
如果int
可以表示源类型的所有值,则除bool
、char16\u t
、char32\u t
或wchar\u t
以外的整数类型的PR值(其整数转换秩(4.13)小于int
可以转换为int
类型的PR值;否则,可以将源prvalue转换为类型为unsigned int
的prvalue
在无范围枚举的情况下,我们将在这里处理int
s。对于作用域的枚举(枚举类
和枚举结构
),不适用整体升级。无论如何,积分提升也不会导致UB,因为存储的值在基础类型的范围内,在int
的范围内
[stmt.开关]/5
执行switch
语句时,将评估其条件并与每个case常量进行比较。如果其中一个case常量等于条件的值,则控制权将传递给匹配的case
标签后面的语句。如果没有与条件匹配的case
常量,并且如果存在default
标签,则控制传递到由default
标签标记的语句
应点击默认值
标签
注意:我们可以再看一看比较运算符,但在引用的“比较”中没有明确使用它。事实上,在我们的例子中,没有任何迹象表明它会为作用域或非作用域枚举引入UB
作为奖励,标准是否对此做出了任何保证,但使用了普通枚举
enum
是否有作用域在这里没有任何区别。但是,底层类型是否固定会有区别。完整的[decl.enum]/7是:
对于基础类型为固定的枚举,枚举的值是基础类型的值。否则,对于emin为最小枚举数且emax为最大枚举数的枚举,枚举的值为i
switch (color) {
// ... red and yellow cases omitted
default:
// handle error
break;
}
enum ColorUnfixed /* no fixed underlying type */
{
red = 0x1,
yellow = 0x2
}