枚举警告:超出范围
Enum warning : outside the range
我有以下代码。有两个枚举。一个有 16 个值 (A_) 和
另一个有 15 个值 (A1_)。
#include <iostream>
typedef enum
{
A_0 = 0,
A_1,
A_2,
A_3,
A_4,
A_5,
A_6,
A_7,
A_8,
A_9,
A_10,
A_11,
A_12,
A_13,
A_14,
A_15,
A_FIRST = A_0,
A_LAST = A_15
} a_t;
typedef enum
{
A1_0 = 0,
A1_1,
A1_2,
A1_3,
A1_4,
A1_5,
A1_6,
A1_7,
A1_8,
A1_9,
A1_10,
A1_11,
A1_12,
A1_13,
A1_14,
A1_FIRST = A1_0,
A1_LAST = A1_14
} a1_t;
int
main()
{
a_t m = static_cast<a_t> (static_cast<int> (A_LAST) + 1); // WARNING
std::cout << m;
a1_t m1 = static_cast<a1_t> (static_cast<int> (A1_LAST) + 1); // NO WARNING
std::cout << m1;
return 0;
}
g++编译:
g++ -Wconversion enum_testing.cpp
我收到一条警告消息:
enum_testing.cpp: In function ‘int main()’:
enum_testing.cpp:49:64: warning: the result of the conversion is unspecified because ‘16’ is outside the range of type ‘a_t’ [-Wconversion]
a_t m = static_cast<a_t> (static_cast<int> (A_LAST) + 1);
问题:为什么我在第一次使用枚举 A_ 声明时收到警告消息,而不是使用枚举 A1_ 的消息。
问题是编译器可以自由选择任何足够大的底层类型来让枚举声明保存它的所有数据。
在你的例子中,它显然选择了一个整数类型来表示 a_t
,它的(可能是虚的)位大小为 4。
此类型只能保存 0 到 15 之间的值。您尝试 static_cast<a_t> (16)
,它超出了可表示的值,因此是未定义的行为。这对于 a1_t
是不正确的 - 你得到了 "lucky" - 因为在这里它将是 static_cast<a1_t> (15)
并且 15 由 a1_t
.
的基础类型表示
enum 的范围是:
[...]If the underlying type is not fixed, the range is all values
possible for the smallest bit field large enough to hold all
enumerators of the target enumeration[...]
所以 15
适合这个范围,而 16
不适合。这是 C++17 之前的未指定行为,之后将是未定义的行为。更改是由于 DR 1766: Values outside the range of the values of an enumeration 表示:
Although issue 1094 clarified that the value of an expression of enumeration type might not be within the range of the values of the enumeration after a conversion to the enumeration type (see 5.2.9 [expr.static.cast] paragraph 10), the result is simply an unspecified value. This should probably be strengthened to produce undefined behavior, in light of the fact that undefined behavior makes an expression non-constant. See also 9.6 [class.bit] paragraph 4.
并且解决方案是使其成为未定义的行为。
我有以下代码。有两个枚举。一个有 16 个值 (A_) 和 另一个有 15 个值 (A1_)。
#include <iostream>
typedef enum
{
A_0 = 0,
A_1,
A_2,
A_3,
A_4,
A_5,
A_6,
A_7,
A_8,
A_9,
A_10,
A_11,
A_12,
A_13,
A_14,
A_15,
A_FIRST = A_0,
A_LAST = A_15
} a_t;
typedef enum
{
A1_0 = 0,
A1_1,
A1_2,
A1_3,
A1_4,
A1_5,
A1_6,
A1_7,
A1_8,
A1_9,
A1_10,
A1_11,
A1_12,
A1_13,
A1_14,
A1_FIRST = A1_0,
A1_LAST = A1_14
} a1_t;
int
main()
{
a_t m = static_cast<a_t> (static_cast<int> (A_LAST) + 1); // WARNING
std::cout << m;
a1_t m1 = static_cast<a1_t> (static_cast<int> (A1_LAST) + 1); // NO WARNING
std::cout << m1;
return 0;
}
g++编译:
g++ -Wconversion enum_testing.cpp
我收到一条警告消息:
enum_testing.cpp: In function ‘int main()’:
enum_testing.cpp:49:64: warning: the result of the conversion is unspecified because ‘16’ is outside the range of type ‘a_t’ [-Wconversion]
a_t m = static_cast<a_t> (static_cast<int> (A_LAST) + 1);
问题:为什么我在第一次使用枚举 A_ 声明时收到警告消息,而不是使用枚举 A1_ 的消息。
问题是编译器可以自由选择任何足够大的底层类型来让枚举声明保存它的所有数据。
在你的例子中,它显然选择了一个整数类型来表示 a_t
,它的(可能是虚的)位大小为 4。
此类型只能保存 0 到 15 之间的值。您尝试 static_cast<a_t> (16)
,它超出了可表示的值,因此是未定义的行为。这对于 a1_t
是不正确的 - 你得到了 "lucky" - 因为在这里它将是 static_cast<a1_t> (15)
并且 15 由 a1_t
.
enum 的范围是:
[...]If the underlying type is not fixed, the range is all values possible for the smallest bit field large enough to hold all enumerators of the target enumeration[...]
所以 15
适合这个范围,而 16
不适合。这是 C++17 之前的未指定行为,之后将是未定义的行为。更改是由于 DR 1766: Values outside the range of the values of an enumeration 表示:
Although issue 1094 clarified that the value of an expression of enumeration type might not be within the range of the values of the enumeration after a conversion to the enumeration type (see 5.2.9 [expr.static.cast] paragraph 10), the result is simply an unspecified value. This should probably be strengthened to produce undefined behavior, in light of the fact that undefined behavior makes an expression non-constant. See also 9.6 [class.bit] paragraph 4.
并且解决方案是使其成为未定义的行为。