g++ 错误? (bool_val ? 0 : 1) 既不返回 0 也不返回 1
Posted
技术标签:
【中文标题】g++ 错误? (bool_val ? 0 : 1) 既不返回 0 也不返回 1【英文标题】:g++ bug? (bool_val ? 0 : 1) returns neither 0 nor 1 【发布时间】:2015-10-05 23:44:57 【问题描述】:我通过这个简单的演示重现了这个问题:
// bool_test_func.cpp
#include <stdio.h>
void func(bool* b)
int a = (*b ? 0 : 1);
printf("%d\n", a); // EXPECT ether 0 or 1 here
// bool_test.cpp
void func(bool* b);
int main()
int n = 128;
func((bool*)&n);
return 0;
-O0编译运行:
g++ -g -O0 -Wall -o bool_test bool_test.cpp bool_test_func.cpp
mikewei@maclinux:~/testing/c++$ ./bool_test
0
-O1编译运行(意外结果):
g++ -g -O1 -Wall -o bool_test bool_test.cpp bool_test_func.cpp
mikewei@maclinux:~/testing/c++$ ./bool_test
129
当我检查-O2 ASM代码时,我认为这是一个g++错误,g++的优化代码总是认为bool值是ether 1或0:
00000000004005e6: 4005e6: 48 83 ec 08 sub $0x8,%rsp 4005ea: 0f b6 37 movzbl (%rdi),%esi 4005ed: 83 f6 01 xor $0x1,%esi #just XOR the bool val 4005f0: 40 0f b6 f6 movzbl %sil,%esi 4005f4: bf 94 06 40 00 移动 $0x400694,%edi 4005f9: b8 00 00 00 00 移动 $0x0,%eax 4005fe: e8 9d fe ff ff callq 4004a0 400603: 48 83 c4 08 添加 $0x8,%rsp 400607:c3 retq 400608: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1) 40060f: 00gcc 版本 4.9.2 (Debian 4.9.2-10)
这是 g++ 设计的行为吗?我怎样才能禁用这个错误的优化? 谢谢~
【问题讨论】:
有趣的#include
.
优化没有错:bool 只能包含 0 或 1。你传入的是一个 int
类型双关语作为 bool
,随之而来的是未定义的行为。
相当大胆的声明,这是一个 gcc 错误...
不确定我是否同意欺骗关闭的原因,假设原始实际上是由于未初始化的变量,与类型双关引起的 ub 无关。
不确定我是否赞成将其作为 UB 的一个很好的例子,还是反对 UB 和对这种“错误优化”的傲慢以及 C 标头和强制转换的使用?
【参考方案1】:
我认为这是一个 g++ 错误。
必须尊重地不同意那里。
如何禁用这个错误的优化?
即使这是可能的,实际上也没有错:-)
您将非 bool 指针作为 bool 指针传递(底层项不是 bool 类型),我很确定这(称为类型双关语)会调用未定义的行为。
因此代码可以随心所欲地做任何事情。
您可以将原型void func(bool* b)
视为您同意只传递指向bool
值的指针的合约。如果您违反该合同,则所有赌注都将取消。在这种特殊情况下,您的代码:
int a = (*b ? 0 : 1);
告诉它将 false 转换为 1,将 true 转换为 0。如果您要提供 valid 输入(false/0
或 true/1
),xor input, 1
将是 完全正确的 做正确的事。
但是,因为你给它128
,xor
的结果是129
。
【讨论】:
同意。该实现似乎实现了一个值为 0 和 1 的 bool。因此,只要 bool 类型只被使用过,它们就可以很容易地用 xor 操作。转换为 int 也很容易,因为底层的 bool 似乎是一个 int,所以不需要转换操作。 这称为类型双关语,标准禁止从 int 到 bool 的类型双关语(N3376 中的第 3.10/10 节)。确实是UB。 问题的最后一部分是如何禁用优化。虽然我强烈建议不要这样做并且不同意发问者将其描述为“错误的优化”,但 gcc 允许您禁用命名优化,以便根据标准编写具有 UB 的代码。-fno-delete-null-pointer-checks
就是一个著名的例子。我还没有检查,但是-fno-strict-aliasing
“修复”了这个代码吗?
啊,我猜不是,因为-O1
不包括-fstrict-aliasing
。尽管如此,如果这是由于命名优化,那么有关它的信息会稍微增强这个答案。
有趣的选择。我想知道考虑 0/非 0 类型的布尔值而不是像这种情况下那样严格的 0/1 类型有多糟糕。 AFAIK,微软采用了cl
的前模型。以上是关于g++ 错误? (bool_val ? 0 : 1) 既不返回 0 也不返回 1的主要内容,如果未能解决你的问题,请参考以下文章
错误:npm install -g @angular/cli
在 Windows 上使用 g++ 编译 C++ 后出现 __gxx_personality_v0 错误
Window10 上的 Webdriverio 错误 basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")