如果enum不能适用于无符号整型,会发生什么?

时间:2022-06-16 16:05:31

As requested by Bathsheba and as a follow up question to "What happens if an enum cannot fit into an integral type?":

应芭丝谢芭的要求,并作为“如果enum不能适合于一个整体类型”的后续问题:

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?

oops的值定义了吗?


MSVS2015 compilation:

MSVS2015编译:

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:

MSVS2015输出:

bar = 4294967295
oops= 0

gcc 4.9.2 compilation:

gcc 4.9.2编译:

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

gcc 4.9.2输出

//compilation failed

1 个解决方案

#1


19  

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.

(dcl。enum)/ 2:[…[参考译文]如果没有初始化器,枚举数定义就会使枚举数通过增加前一个枚举数的值而得到的值。

Therefore, the value of foo::undefined in our example is 2 (true+1). Which can not be represented as a bool.

因此,在我们的示例中,foo::undefined的值为2 (true+1)。不能用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.

(dcl。枚举类型不固定的枚举,[…]如果没有整数类型可以表示所有的枚举数值,那么枚举是病态的。

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:

可能的值为foo::定义:

  • Highest possible value (true): undefined and oops should be underlying type's maximum value.
  • 最高可能值(true): undefined和oops应该是底层类型的最大值。
  • 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).
  • 最小可能值(false):底层类型的最小值。注意:在有符号整数中,它不匹配整数溢出(未定义行为)的当前行为。
  • 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).

所有这些值的问题是,它可能会产生两个具有相同值的字段(例如: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.

(dcl。enum]/5:如果基础类型是固定的,那么在闭括号之前的每个枚举数的类型都是基础类型,而枚举定义中的常量表达式应该是基础类型的转换常量表达式。

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.

然后bar::undefined为真。在“隐式”初始化器中,情况并非如此:这个标准段落只表示初始化器,而不是“隐式”初始化器。

Summary

  1. With this way, it is possible for an enum with a fixed-underlying-type to have unrepresentable values.
  2. 通过这种方式,具有固定-underlying类型的enum可能具有不可表示的值。
  3. Their value is undefined by the standard.
  4. 它们的值不受标准的定义。

According to the question and comments, this is not valid in GCC and clang but valid for MSVS-2015 (with a warning).

根据问题和评论,这在GCC和clang中是无效的,但是对于MSVS-2015(有警告)是有效的。

#1


19  

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.

(dcl。enum)/ 2:[…[参考译文]如果没有初始化器,枚举数定义就会使枚举数通过增加前一个枚举数的值而得到的值。

Therefore, the value of foo::undefined in our example is 2 (true+1). Which can not be represented as a bool.

因此,在我们的示例中,foo::undefined的值为2 (true+1)。不能用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.

(dcl。枚举类型不固定的枚举,[…]如果没有整数类型可以表示所有的枚举数值,那么枚举是病态的。

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:

可能的值为foo::定义:

  • Highest possible value (true): undefined and oops should be underlying type's maximum value.
  • 最高可能值(true): undefined和oops应该是底层类型的最大值。
  • 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).
  • 最小可能值(false):底层类型的最小值。注意:在有符号整数中,它不匹配整数溢出(未定义行为)的当前行为。
  • 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).

所有这些值的问题是,它可能会产生两个具有相同值的字段(例如: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.

(dcl。enum]/5:如果基础类型是固定的,那么在闭括号之前的每个枚举数的类型都是基础类型,而枚举定义中的常量表达式应该是基础类型的转换常量表达式。

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.

然后bar::undefined为真。在“隐式”初始化器中,情况并非如此:这个标准段落只表示初始化器,而不是“隐式”初始化器。

Summary

  1. With this way, it is possible for an enum with a fixed-underlying-type to have unrepresentable values.
  2. 通过这种方式,具有固定-underlying类型的enum可能具有不可表示的值。
  3. Their value is undefined by the standard.
  4. 它们的值不受标准的定义。

According to the question and comments, this is not valid in GCC and clang but valid for MSVS-2015 (with a warning).

根据问题和评论,这在GCC和clang中是无效的,但是对于MSVS-2015(有警告)是有效的。