c++ - clang++ 的选项 -fno-strict-enums 有什么作用?
问题描述
两个月前,我作为一个clang++
错误报告了下面的 C++ 程序z
在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-枚举
允许编译器使用枚举类型的值只能是枚举值之一的假设进行优化(如 C++ 标准中定义的那样;基本上,可以用表示所有枚举器)。如果程序使用强制转换将任意整数值转换为枚举类型,则此假设可能无效。
请注意,仅-fstrict-enums
记录了该选项,但似乎很清楚禁用启用-fno-strict-enums
的编译器行为。-fstrict-enums
我无法针对 GCC 的文档提交错误,因为生成设置z
为的二进制文件,-1
我理解-fno-strict-enums
的要求正是这样g++ -O2 -fno-strict-enums
做的。
谁能告诉我-fno-strict-enums
Clang 中的作用(如果我误解了它在 GCC 中的作用,还有 GCC 中的作用),以及该选项的值在 Clang 的任何地方是否有任何影响?
作为参考,我的错误报告在这里,并且显示我的意思的编译器资源管理器链接在这里。用作参考的版本是针对 I32LP64 架构的 Clang 10.0.1 和 GCC 10.2。
解决方案
的效果-fno-strict-enums
是取消-fstrict-enums
。也就是说,不允许编译器使用枚举类型的值只能是枚举值之一的假设进行优化。我想强调一下,选择这个词是“允许的”,而不是“必需的”。可能很难看到不再允许最初未完成的事情的影响。不过,我想我已经找到了一个可以看到这一点的例子。
首先,我想在问题的背景下澄清“枚举的价值”。枚举e
有两个枚举器,其值为0
和1
。表示这些值所需的最小位数是 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
只能保持0
或1
很明显它只是被赋予了不同的值。(这种干扰并不取决于4294967295
对于 32 位有符号整数来说是否太大,而仅仅4294967295
是作为编译时值。作为另一个示例,分配(enum e) 2
toe
也会导致这种干扰。)
专注于作业y = e > e1
。如果-fno-strict-enums
有效,则唯一可用的优化是替换e1
为0
. 但是,如果我们可以假设e
只能是0
或1
(枚举的值,恰好也是枚举数的值),则可以使用另一种优化。
如果e
是0
,则以下具有相同的值:
(long long) (e > e1)
(long long) (0 > 0)
(long long) false
(long long) e
如果e
是1
,则以下具有相同的值:
(long long) (e > e1)
(long long) (1 > 0)
(long long) true
(long long) e
在任何一种情况下,我们都可以跳过比较并简单地e
转换为 a long long
。这反映在由 clang 10 为 line 生成的程序集中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
这是不允许的-fno-strict-enums
。
推荐阅读
- flutter - 如何更改 Flutter WEB 中的“状态栏”颜色?(保存为书签后)
- object-detection - Google AutoML Vision:能够对独特但相似的对象进行精确匹配?
- angular - 为什么 ngFor 循环遍历 JSON 数组但返回空属性值?
- r - 在 R 中读取 xlsx 文件时,路径必须是字符串错误
- javascript - javascript window.close() 不起作用
- r - 重复序列 R
- c - 在 C 中使用 str_tok 嵌套拆分
- bootstrap-4 - 多个模态在一个 div 下覆盖两个模态
- c# - 多个应用程序的运行问题 - System.InvalidOperationException
- javascript - Puppeteer:如何监听 http 响应,直到找到正确的响应?