【发布时间】:2019-02-09 08:15:45
【问题描述】:
我正在尝试编写一些宏以安全使用_Bool,然后对我的代码进行压力测试。为了邪恶的测试目的,我想出了这个肮脏的黑客:
_Bool b=0;
*(unsigned char*)&b = 42;
鉴于 _Bool 在实现 sizeof(_Bool)==1 上是 1 个字节),我看不出这种 hack 是如何违反 C 标准的。这不应该是严格的别名违规。
然而,当通过各种编译器运行这个程序时,我遇到了问题:
#include <stdio.h>
int main(void)
{
_Static_assert(sizeof(_Bool)==1, "_Bool is not 1 byte");
_Bool b=0;
*(unsigned char*)&b = 42;
printf("%d ", b);
printf("%d", b!=0 );
return 0;
}
(代码依赖printf隐式默认参数提升为int)
某些版本的 gcc 和 clang 输出 42 42,其他版本输出 0 0。即使禁用了优化。我会期待42 1。
似乎编译器假定_Bool 只能是1 或0,但同时它在第一种情况下很高兴打印42。
Q1:为什么会这样?上面的代码是否包含未定义的行为?
Q2:sizeof(_Bool) 的可靠性如何? C17 6.5.3.4 根本没有提到_Bool。
【问题讨论】:
-
输出怎么可能是
42 42?第二个 printf 只能打印 1 或 0。 -
O_O I tried it。我的心现在被严重炸毁了。这加入了我收集的 UB 示例。
-
我不知道。虽然我最初对第二个 42 感到震惊,但回想起来还是有道理的。因为
b != 0的_Bool可以优化为简单的b。不过我还在摸不着头脑。 -
@RbMm 字符类型在严格的别名规则中是一个例外。优化器无法基于此处导致 UB。
-
请发布已发布问题的汇编代码。然后我们可以很容易地确定编译器在想什么
标签: c boolean language-lawyer c11 strict-aliasing