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: 00

gcc 版本 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/0true/1),xor input, 1 将是 完全正确的 做正确的事。

但是,因为你给它128xor 的结果是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的主要内容,如果未能解决你的问题,请参考以下文章

我如何从angular2 final(2.0.1)传递简单数据(json)

如何将补丁应用于 Richfaces 4.0.0.Final

BZOJ 3727 Final Zadanie

CF [2016-2017 ACM-ICPC CHINA-Final][GYM 101194 H] Great Cells

2018 China Collegiate Programming Contest Final (CCPC-Final 2018)(A B G I L)

[CODE FESTIVAL 2016 Final]G - Zigzag MST——MST