如果枚举不能适应无符号整数类型,会发生什么情况? [英] What happens if an enum cannot fit into an unsigned integral type?
问题描述
根据 Bathsheba 的要求,以及作为后续问题,如果枚举不能适合整数类型会发生什么?:
由于枚举定义如下:
枚举foo:unsigned int
{
bar = UINT_MAX,
oops
};
是 oops
的值定义还是isn是吗?
MSVS2015汇编:
警告C4340:'oops':值从正值到负值
警告C4309:'initializing':截断常量值
警告C4369:'oops':enumerator value' 4274967296'不能表示为'unsigned int',值为'0'
MSVS2015输出:
bar = 4294967295
oops = 0
gcc 4.9.2编译:
9:注意:在扩展宏'UINT_MAX'
bar = UINT_MAX,
^
10:错误:枚举值4294967296l超出了底层类型unsigned int的范围
oops
^
编译失败
gcc 4.9.2 output
//编译失败
这是一个非常有趣的问题。简单的答案是,这是字面上未定义:标准不说任何关于这种情况。
要想有更好的例子,请考虑枚举
:
enum foo:bool {True = true,undefined};
根据标准:
[ dcl.enum ] / 2 :[...]没有初始值设定为枚举器提供上一个枚举器的值。
因此,在我们的示例中 foo :: undefined
的值为 2
code> true + 1 )。
b
否,根据标准,它是完全有效的,只有未固定的底层类型有一个限制,无法表示所有的枚举值:
[ dcl.enum ] / 7 : [...]如果没有整数类型可以表示所有的枚举值,枚举是不成立的。
它没有说明一个不能表示所有枚举值的固定的底层类型。
问题 oops
和未定义
?
> undefined :标准没有说明这种情况。
可能的值foo :: undefined
:
- 最高可能值(
true
):undefined
和oops
应为底层类型的最大值。 - 最低可能值(
false
):底层类型的最小值。注意:在有符号整数中,它不会匹配当前的整数溢出行为(未定义的行为)。 - 随机值(?):编译器将选择一个值。
所有这些值的问题是它可能导致两个具有相同值的字段(例如 foo :: True == (例如
undefined = 2) 之间的区别(
< )和implicit初始值设定项(例如
True = true,undefined
) 到标准:
[ dcl.enum ] / 5 :如果底层类型是固定的,在大括号之前的每个枚举的类型是底层类型和枚举器定义中的常量表达式
换句话说:
枚举栏:bool {undefined = 2};
相当于
枚举栏:bool {undefined = static_cast< bool>(2)};
然后 bar :: undefined
true
。在隐式初始化器中,不是这种情况:这个标准段落仅仅关于 initializer ,而不是关于隐式初始化器。
摘要
- 这样,
枚举
b
$ b
根据问题和意见,这在GCC和clang中无效,但对MSVS-2015有效(带有警告)。
As requested by Bathsheba and as a follow up question to "What happens if an enum cannot fit into an integral type?":
Asuming an enum is defined as follows :
enum foo : unsigned int
{
bar = UINT_MAX,
oops
};
Is the value of oops
defined or isn't it?
MSVS2015 compilation:
warning C4340: 'oops': value wrapped from positive to negative value
warning C4309: 'initializing': truncation of constant value
warning C4369: 'oops': enumerator value '4294967296' cannot be represented as 'unsigned int', value is '0'
MSVS2015 output:
bar = 4294967295
oops= 0
gcc 4.9.2 compilation:
9 : note: in expansion of macro 'UINT_MAX'
bar = UINT_MAX,
^
10 : error: enumerator value 4294967296l is outside the range of underlying type 'unsigned int'
oops
^
Compilation failed
gcc 4.9.2 output
//compilation failed
This is a very interesting question. The simple answer is that this is literally undefined: the standard doesn't say anything about this case.
To have a better example, consider this enum
:
enum foo : bool { True=true, undefined };
According to the standard:
[dcl.enum]/2: [...] An enumerator-definition without an initializer gives the enumerator the value obtained by increasing the value of the previous enumerator by one.
Therefore, the value of foo::undefined
in our example is 2
(true+1
). Which can not be represented as a bool
.
Is it ill-formed?
No, according to the standard, it is perfectly valid, only not-fixed underlying type have a restriction about not being able to represent all of the enumerator values:
[dcl.enum]/7: For an enumeration whose underlying type is not fixed, [...] If no integral type can represent all the enumerator values, the enumeration is ill-formed.
It says nothing about a fixed underlying type that can not represent all the enumerator values.
What is the value of original question's oops
and undefined
?
It is undefined: the standard doesn't say anything about this case.
Possible values for foo::undefined
:
- Highest possible value (
true
):undefined
andoops
should be underlying type's maximum value. - Lowest possible value (
false
): the underlying type's minimum value. Note: In signed integers, it would not match the current behavior for Integer overflow (undefined behavior). - Random value (?): the compiler will choose an value.
The problem with all of these values is that it may result two fields with the same value (e.g. foo::True == foo::undefined
).
The difference between initializer (e.g. undefined=2
) and "implicit" initializer (e.g. True=true, undefined
)
According to the standard:
[dcl.enum]/5: If the underlying type is fixed, the type of each enumerator prior to the closing brace is the underlying type and the constant-expression in the enumerator-definition shall be a converted constant expression of the underlying type.
In other words:
enum bar : bool { undefined=2 };
is equivalent to
enum bar : bool { undefined=static_cast<bool>(2) };
And then bar::undefined
will be true
. In an "implicit" initializer, it would not be the case: this standard paragraph say it about only initializer, and not about "implicit" initializer.
Summary
- With this way, it is possible for an
enum
with a fixed-underlying-type to have unrepresentable values. - Their value is undefined by the standard.
According to the question and comments, this is not valid in GCC and clang but valid for MSVS-2015 (with a warning).
这篇关于如果枚举不能适应无符号整数类型,会发生什么情况?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!