如何设置int范围之外的枚举常量的值?

Vil*_*ray 8 c enums enumeration c99 language-lawyer

C99标准要求用于定义枚举常量值的表达式具有可表示为的值int.

在C99标准第6.7.2.2节第2 节中:

定义枚举常量值的表达式应为整数常量表达式,其值可表示为int.

但是,枚举类型可以由实现定义为与任何整数类型兼容,包括那些值范围之外的整数类型int.

在C99标准第6.7.2.2节第2 节中:

每个枚举类型应与char有符号整数类型或无符号整数类型兼容.

这意味着虽然您无法在a的范围之外显式设置枚举常量int的值,但是int如果实现将枚举类型与具有范围的整数类型兼容,则枚举常量的值可以在a的范围之外.在...之外int.


现在我知道一种方法来获取int枚举常量的set 范围之外的特定值:虚拟枚举器.

enum hack{
    DUMMY0 = INT_MAX,
    DUMMY1,
    /* supply as many more dummy enumerators as needed */
    ...
    /* declare desired enumerator */
    FOOBAR
};
Run Code Online (Sandbox Code Playgroud)

这要归功于C99标准第6.7.2.2节第3段:

枚举器=将其枚举常量定义为常量表达式的值.
...
每个后续的枚举器都没有= 将其枚举常量定义为通过将1添加到前一个枚举常量的值而获得的常量表达式的值.

不幸的是,这仅适用于大于的正值INT_MAX,因为每个后续枚举器的值只会递增.另一个需要注意的是,需要创建可能的许多虚拟枚举器,以获取所需的特定枚举器.


这导致以下问题:

  1. 有没有办法将枚举常量的值设置为超出范围的负值int
  2. 有没有更好的方法在枚举常数范围之外设置正值int
  3. 关于我的虚拟枚举器 hack,C99标准是否对可以在单个声明的枚举数设置了限制enum

Kei*_*son 10

如何设置int范围之外的枚举常量的值?

你没有.

C99标准要求用于定义枚举常量值的表达式具有可表示为的值int.

是的,C11标准没有改变任何一个.

但是,枚举类型可以由实现定义为与任何整数类型兼容,包括那些值范围之外的整数类型int.

也正确.

这意味着虽然您无法在a的范围之外显式设置枚举常量int的值,但是int如果实现将枚举类型与具有范围的整数类型兼容,则枚举常量的值可以在a的范围之外.在...之外int.

这是不正确的,但我认为你发现标准中的措辞存在缺陷.(更新:我认为这不是一个弱点;见下文).你引用了6.7.2.2:

定义枚举常量值的表达式应为整数常量表达式,其值可表示为 int.

这似乎只适用于由显式表达式定义的值,而不是像这样的情况:

enum too_big {
    big = INT_MAX,
    even_bigger
};
Run Code Online (Sandbox Code Playgroud)

但这实际上并不起作用,因为它even_bigger被声明为类型的常量int,显然不具有该值INT_MAX + 1.

我强烈怀疑的意图是,上述声明是非法的(违反约束); 应该重新编写6.7.2.2以使其更清晰.(更新:我现在认为它已经足够清楚了;见下文.)

gcc的作者似乎同意我的看法:

$ cat c.c
#include <limits.h>
enum huge {
    big = INT_MAX,
    even_bigger
};
$ gcc -c c.c
c.c:4:5: error: overflow in enumeration values
Run Code Online (Sandbox Code Playgroud)

因此,即使您的解释是正确的,您也不太可能编写和使用依赖于它的代码.

解决方法是使用整数(无论如何,枚举类型或多或少都是伪装的整数).一个const整数对象不是一个常量表达式,不幸的是,所以你可能不得不求助于使用预处理:

typedef long long huge_t;
#define big ((huge_t)INT_MAX)
#define even_bigger (big + 1)
Run Code Online (Sandbox Code Playgroud)

这假设long long宽度大于int,可能但不保证(如果至少为64位int,则long long可以是相同的大小int).

你的问题1和2的答案是否定的; 你不能在范围之外定义一个负数或正数的枚举常量int.

至于你的问题3,C11标准的5.2.4.1节(大致)说,编译器必须在单个枚举中支持至少 1023个枚举常量.大多数编译器实际上没有强加固定限制,但是在任何情况下,所有常量都必须具有范围内的值INT_MIN.. INT_MAX,这对你没有多大帮助.(同一类型中的多个枚举常量可以具有相同的值.)

(翻译限制要求实际上比这更复杂.编译器必须支持至少一个程序,其中包含所有枚举列表的至少一个实例.这是一个相当无用的要求,如上所述.目的是最简单的方法满足标准要求是为了避免施加任何固定限制.)

更新:

我在comp.std.c Usenet新闻组中提出了这个问题.Tim Rentsch在讨论中提出了一个很好的观点,我现在认为:

enum too_big {
    big = INT_MAX,
    even_bigger
};
Run Code Online (Sandbox Code Playgroud)

是违反约束,需要编译器诊断.

我担心的是禁止在以下范围之外的明确值的措辞int:

定义枚举常量值的表达式应为整数常量表达式,其值可表示为 int.

不适用,因为没有涉及(显式)表达.但6.7.7.2p3说:

具有no =的每个后续枚举器将其枚举常量定义为通过将1添加到先前枚举常量的值而获得的常量表达式的值.

(重点补充).所以有一个表达式,其值必须可以表示为int; 它只是没有出现在源代码中.我对此并不是很满意,但我会说意图非常明确.

这是关于comp.std.c 的讨论.