clang ++的选项-fno-strict-enums有什么作用?

问题描述

两个月前,我报告了一个clang++错误,它是使用z编译时,下面的C ++程序将4294967295设置为clang++ -O2 -fno-strict-enums

enum e { e1,e2 } e;

long long x,y,z;

char *p;

void f(void) {
    e = (enum e) 4294967295;
    x = (long long) e;
    y = e > e1;
    z = &p[e] - p;
}

由于该程序未定义,我的错误报告被关闭为无效。我的感觉是使用选项-fno-strict-enums对其进行了定义。

据我所知,Clang没有值得称呼的文档,因为它的目的是在接受的选项及其含义方面与GCC兼容。我阅读了GCC关于选项-fno-strict-enums的文档,说该程序应将z的值设置为-1

-fstrict-enums

允许编译器使用枚举类型的值只能是枚举值之一的假设进行优化 (如C ++标准中所定义;基本上,该值可以是 以代表所有 枚举数)。如果程序使用以下命令,则此假设可能无效: 强制将任意整数值转换为枚举类型。

请注意,仅记录了选项-fstrict-enums,但似乎很清楚,-fno-strict-enums禁用了-fstrict-enums启用的编译器行为。我无法针对GCC的文档提出错误,因为生成的二进制文件将z强制设置为-1-fno-strict-enums正是将g++ -O2 -fno-strict-enums设置为-fno-strict-enums。 >

有人能告诉我{{1}}在Clang中的作用吗(如果我误解了它在GCC中的作用,那么在GCC中),以及选项的值是否对Clang的任何地方都有效?

作为参考,我的错误报告是here,并且显示我的意思的Compiler Explorer链接是here。用作参考的版本是针对I32LP64体系结构的Clang 10.0.1和GCC 10.2。

解决方法

-fno-strict-enums的作用是取消-fstrict-enums。也就是说,不允许编译器使用枚举类型的值只能是枚举值之一的假设进行优化。我想强调,选择一词是“允许的”,而不是“必需的”。可能很难看到不再允许一开始没有做的事情的影响。不过,我想我已经找到了一个可以看到这种情况的例子。

首先,我想在问题上下文中阐明“枚举的值”。枚举e有两个枚举,分别为值01。表示这些值所需的最少位数是1。因此,枚举的值都是可以用1位表示的所有值。在这种情况下,这恰好与枚举器的值一致,但在其他示例中无法保证。

接下来,让我们从问题的代码中删除一行。

enum e { e1,e2 } e;

long long x,y,z;

char *p;

void f(void) {
    //e = (enum e) 4294967295;
    x = (long long) e;
    y = e > e1;
    z = &p[e] - p;
}

我删除的行会干扰strict-enum标志。当编译器确切知道e的值时,该标志使编译器可以做出不必要的假设。编译器可以合理地选择不假定e仅可以容纳01,因为很显然它只是被赋予了不同的值。 (此干扰不取决于4294967295对于32位有符号整数而言太大,而仅取决于4294967295作为编译时值。作为另一个示例,分配{{1} }到(enum e) 2也会造成这种干扰。)

关注作业e。如果y = e > e1有效,唯一可用的优化是将-fno-strict-enums替换为e1。但是,如果我们假设0只能是e0(枚举的值,恰好也是枚举器的值),则可以使用另一种优化方法。

如果1e,则以下各项具有相同的值:

  • 0
  • (long long) (e > e1)
  • (long long) (0 > 0)
  • (long long) false

如果(long long) ee,则以下各项具有相同的值:

  • 1
  • (long long) (e > e1)
  • (long long) (1 > 0)
  • (long long) true

在任何一种情况下,我们都可以跳过比较,只需将(long long) e强制转换为e。这反映在c 10为行long long生成的程序集中。

使用y = e > e1

-fstrict-enums

使用movq %rax,y(%rip)

-fno-strict-enums

xorl %ecx,%ecx testl %eax,%eax setg %cl movq %rcx,y(%rip) 进行了优化,而-fstrict-enums则不允许这样做。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...