是枚举 { a } e = 1;有效的?

Is enum { a } e = 1; valid?

一个简单的问题:enum { a } e = 1;有效吗?

换句话说:在枚举常量的值集中不存在的值是否会导致明确定义的行为?

演示:

$ gcc t0.c -std=c11 -pedantic -Wall -Wextra -c
<nothing>

$ clang t0.c -std=c11 -pedantic -Wall -Wextra -c
<nothing>

$ icc t0.c -std=c11 -pedantic -Wall -Wextra -c
t0.c(1): warning #188: enumerated type mixed with another type
# note: the same warning for enum { a } e = 0;

$ cl t0.c /std:c11 /Za /c
<nothing>

来自6.7.2.2中的C18标准:

Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, but shall be capable of representing the values of all the members of the enumeration.

所以 enum { a } e = 1; 是有效的。 e 是 'integer' 类型,因此它可以取值 11 不作为枚举值存在这一事实没有问题。 枚举成员只为一些可能的值提供方便的标识符。

我在this Draft C11 Standard (in terms of "constraints") that prohibits an assignment to a enum type such as yours (and the C18 Standard quoted in 中找不到任何参考使用基本相同的措辞)。

但是,C11 草案确实在 附件 I – 常见警告中提供了这一点

1     An implementation may generate warnings in many situations, none of which are specified as part of this International Standard. The following are a few of the more common situations.

2

   —    A value is given to an object of an enumerated type other than by assignment of an enumeration constant that is a member of that type, or an enumeration object that has the same type, or the value of a function that returns the same enumerated type (6.7.2.2).

但是建议的警告同样适用于 enum { a } e = 0; 这样的赋值,其中 RHS 对应于 一个有效的枚举常量,但它 实际上 既不是该类型的枚举常量,也不是该枚举类型的对象。

在 C 中有效

这在 C 中有效,例如202x working draft:

6.7.2.2/4 Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, but shall be capable of representing the values of all the members of the enumeration

特别是由于“兼容类型”要求:

6.2.7/1 Two types have compatible type if their types are the same. Additional rules [...]


... implementation-defined 和 C++14 和 earlier/C++17 及更高版本中可能的 unspecified/undefined 行为

虽然超出了此问答的范围(C 标记,而不是 C++),但有趣的是要指出 C++ 并不适用,其中“C 风格”无范围枚举没有固定的底层类型具有微妙的意义与C的区别,C++案例详见以下Q&A:

简而言之

根据枚举类型的定义、兼容类型的转换规则和兼容性保证,1的特定值保证了enum { a } e = 1;的有效性,综合了不同的原因。

剧透警报:在 C18 中,它比任何单个段落的引用都复杂得多(请参阅我在接受的答案下的评论)。

完整解释

我将逐步引用C18标准(准确地说是N2176)。亮点来自我。

首先,我们知道enum { a }是一个整数类型:

6.2.5. Types
16: An enumeration comprises a set of named integer constant values. Each distinct enumeration constitutes a different enumerated type.
17: The type char, the signed and unsigned integer types, and the enumerated types are collectively called integer types.

然后,我们可以证明如果 enum { a } 是一个“足够大”以容纳 1 的整数类型,则赋值将有效(因为没有明确的相反声明):

6.2.7 Compatible types and composite types
1:Two types have compatible type if their types are the same. (...)

6.3. Conversions
2: Unless explicitly stated otherwise, conversion of an operand value to a compatible type causes no change to the value or the representation.

6.7.2.2 Enumeration specifiers
4: Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, but shall be capable of representing the values of all the members of the enumeration.

但是字体够大吗?从这里我们推导出a的值为0。由于它也是集合中最大的枚举常量,我们可以推断 enum { a } “至少”与 char 兼容:

6.7.2.2 Enumeration specifiers
3: (...) An enumerator with = defines its enumeration constant as the value of the constant expression. If the first enumerator has no =, the value of its enumeration constant is 0. Each subsequent enumerator with no = defines its enumeration constant as the value of the constant expression obtained by adding 1 to the value of the previous enumeration constant.

总之,赋值是合法的,因为文字1也兼容char

注意依赖于实现的假设!

但请注意,这样的整数赋值不一定对您选择的任何整数有效:

enum { a } = INT_MAX;  // Implementation dependent, see J.3.9 
enum { a, b=INT_MAX } = 1024;  // ok: b requires int as compatible type  

第一种情况,枚举只保证兼容char。但我们无法保证它与 int:

兼容

J.3. Implementation-defined behavior
(...) **J.3.9. Structures, unions, enumerations, and bit-fields
(...)

  • The integer type compatible with each enumerated type (6.7.2.2).

在第二种情况下,我们使用了一个整数值的规范来强制与 int 兼容的类型。