gpt4 book ai didi

c++ - 如果您向枚举类 static_cast 无效值会发生什么?

转载 作者:行者123 更新时间:2023-12-01 16:56:30 25 4
gpt4 key购买 nike

考虑这个 C++11 代码:

enum class Color : char { red = 0x1, yellow = 0x2 }
// ...
char *data = ReadFile();
Color color = static_cast<Color>(data[0]);

假设 data[0] 实际上是 100。根据标准设置的颜色是什么?
特别是,如果我以后做
switch (color) {
// ... red and yellow cases omitted
default:
// handle error
break;
}

标准是否保证将达到默认值?如果不是,那么在这里检查错误的正确、最有效、最优雅的方法是什么?

编辑:

作为奖励,标准是否对此做出任何保证,但使用简单的枚举?

最佳答案

What is color set to according to the standard?



引用来自 C++11 和 C++14 标准的引用来回答:

[expr.static.cast]/10

A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values (7.2). Otherwise, the resulting value is unspecified (and might not be in that range).



我们查一下枚举值的范围:[dcl.enum]/7

For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type.



CWG 1766 之前(C++11、C++14)
因此,对于 data[0] == 100 ,结果值被指定(*),并且没有 Undefined Behaviour (UB)涉及。更一般地,当您从基础类型转换为枚举类型时, data[0] 中没有值。可能导致 static_cast 的 UB .

CWG 1766 (C++17) 之后
CWG defect 1766 .
[expr.static.cast]p10 段落已得到加强,所以您现在 可以 如果将枚举可表示范围之外的值转换为枚举类型,则调用 UB。这仍然不适用于问题中的场景,因为 data[0]是枚举的基础类型(见上文)。

请注意,CWG 1766 被认为是标准中的一个缺陷,因此编译器实现者可以将其应用于他们的 C++11 和 C++14 编译模式。

(*) char要求至少为 8 位宽,但不要求为 unsigned .可存储的最大值要求至少为 127根据 C99 标准的附录 E。

与 [expr]/4 比较

If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined.



在 CWG 1766 之前,转换整数类型 -> 枚举类型可以产生一个未指定的值。问题是:未指定的值是否可以超出其类型的可表示值?我相信答案是 -- 如果答案是肯定的,那么“此操作产生未指定的值”和“此操作具有未定义的行为”之间对有符号类型的操作所获得的保证不会有任何区别。

因此,在 CWG 1766 之前,甚至 static_cast<Color>(10000)不是 调用UB;但在 CWG 1766 之后,它 调用UB。

现在, switch陈述:

[stmt.switch]/2

The condition shall be of integral type, enumeration type, or class type. [...] Integral promotions are performed.



[转换.prom]/4

A prvalue of an unscoped enumeration type whose underlying type is fixed (7.2) can be converted to a prvalue of its underlying type. Moreover, if integral promotion can be applied to its underlying type, a prvalue of an unscoped enumeration type whose underlying type is fixed can also be converted to a prvalue of the promoted underlying type.



注意:不带 enum-base 的作用域枚举的基础类型是 int .对于无作用域枚举,底层类型是实现定义的,但不应大于 int如果 int可以包含所有枚举器的值。

对于 无作用域枚举 , 这导致我们/1

A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int.



的情况下无作用域 枚举,我们将处理 int在这里。对于 范围枚举( enum classenum struct ),不适用积分促销。无论如何,积分提升也不会导致 UB,因为存储的值在基础类型的范围内,并且在 int 的范围内。 .

[stmt.switch]/5

When the switch statement is executed, its condition is evaluated and compared with each case constant. If one of the case constants is equal to the value of the condition, control is passed to the statement following the matched case label. If no case constant matches the condition, and if there is a default label, control passes to the statement labeled by the default label.


default标签应该被击中。

注意:人们可以再看一下比较运算符,但它没有明确用于引用的“比较”中。事实上,在我们的例子中,没有任何迹象表明它会为作用域或非作用域枚举引入 UB。

As a bonus, does the standard make any guarantees as about this but with plain enum?



是否 enum is scoped 在这里没有任何区别。但是,基础类型是否固定确实有所不同。完整的 [decl.enum]/7 是:

For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type. Otherwise, for an enumeration where emin is the smallest enumerator and emax is the largest, the values of the enumeration are the values in the range bmin to bmax, defined as follows: Let K be 1 for a two's complement representation and 0 for a one's complement or sign-magnitude representation. bmax is the smallest value greater than or equal to max(|emin| − K, |emax|) and equal to 2M − 1, where M is a non-negative integer. bmin is zero if emin is non-negative and −(bmax + K) otherwise.



我们来看看下面的枚举:
enum ColorUnfixed /* no fixed underlying type */
{
red = 0x1,
yellow = 0x2
}

请注意,我们不能将其定义为作用域枚举,因为所有作用域枚举都具有固定的基础类型。

幸运的是, ColorUnfixed的最小枚举数是 red = 0x1 ,所以 max(|emin| − K , |emax|) 等于 |emax|无论如何,这是 yellow = 0x2 .大于或等于 2 的最小值,对于正整数 M 等于 2M - 1是 3 (22 - 1)。 (我认为目的是允许范围以 1 位步长扩展。)因此 bmax 是 3 bmin 是 0 .

因此, 100将超出 ColorUnfixed 的范围,以及 static_cast将在 CWG 1766 之前产生未指定的值,在 CWG 1766 之后产生未定义的行为。

关于c++ - 如果您向枚举类 static_cast 无效值会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18195312/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com