为什么枚举值可以有大于 int 的值?

3

我定义了一个枚举如下:

typedef enum { x = 1ULL<<40 } e;

看起来表达式“x”计算结果为1UL<<40。

然而,C11 6.4.4.3规定:“声明为枚举常量的标识符的类型为int。”

顺便说一下,这救了我的一天,因为我想要枚举值>1<<32。然而,我需要知道如何做到这一点;我有点紧张编写不符合标准的代码。

我尝试了这段代码:

int main() {
        printf("%zu %zu %lx\n", sizeof(e), sizeof(x), x);
        return 0;
}

使用 gcc -std=c11 -Wall 进行编译 (gcc 8.3.1, linux x86_64), 输出为:8 8 10000000000

如果将 %lx 改为 %llx,将会收到一个编译警告,但输出结果相同,这表明 x 的大小为 long。

根据我的阅读理解,我期望会收到编译警告和输出 4 4 0


每个枚举类型都应与char、有符号整数类型或无符号整数类型兼容。类型的选择是实现定义的。据我所知,宽类型是可以的,但1ULL<<40不行。嗯嗯。 - chux - Reinstate Monica
请注意,我正在违反§6.7.2.2 2条款,该条款规定枚举常量必须具有可表示为“int”的值。因此,根据规范,我的代码无效。也许这使他们能够在不违反规范的情况下扩展语言? - Erik Carstensen
我不会依赖这段代码能够正常工作,而是会寻找另一种解决方案。 - Carey Gregory
1个回答

3

编译器扩展。例如,使用clang:

$ CFLAGS=-Weverything make example && ./example
cc -Weverything    example.c   -o example
example.c:3:16: warning: ISO C restricts enumerator values to range of 'int'
      (1099511627776 is too large) [-Wpedantic]
typedef enum { x = 1ULL<<40 } e;
               ^   ~~~~~~~~
1 warning generated.
8 8 10000000000

使用gcc编译器:

$ CFLAGS='-Wall -pedantic' make example && ./example
cc -Wall -pedantic    example.c   -o example
example.c:3:20: warning: ISO C restricts enumerator values to range of ‘int’ [-Wpedantic]
 typedef enum { x = 1ULL<<40 } e;
                    ^~~~
8 8 10000000000

这些警告很好,但对我来说,似乎clang和gcc都产生了不正确的行为;规范确实说sizeof(x)应该等于4,而不是8。他们怎么能逃脱这个问题呢?有没有一些我错过的gcc标志可以给我输出“4 4 0”?或者他们可以声称sizeof可能是8,因为某个地方存在未定义的行为? - Erik Carstensen
1
@ErikCarstensen 规范并未说明任何类型的大小应该等于4。此外,规范规定,如果程序存在约束违规,则编译器应发出诊断信息,它已经执行了这项任务。(因此,规范并未定义这种程序的行为)。您可以使用编译器标志(例如-pedantic-errors-Werror)来防止生成可执行文件。 - M.M
从技术上讲,我认为这应该是一个变体(它不是标准C),而不是扩展。如果标准规定类型为“int”,而实现中的类型不是“int”,则该实现不符合C标准。(我们可以编写一个严格符合标准的程序来检测差异。) - Eric Postpischil
6.7.2.2描述了其他可能的类型,所以谁知道呢。 - Carl Norum
@M.M回答了我的问题。@EricPostpischil,我不理解如何编写符合规范的程序来检测差异,因为§6.7.2.2第2条规定枚举常量的值应表示为“int”。 - Erik Carstensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接