使用GCC6和下面的代码片段,这个测试
if (i > 31 || i < 0) {是false,并且执行此printf。
printf("i > 31 || i < 0 is FALSE, where i=%d", i);并产生这个非常奇怪的输出(GCC6):
i > 31 x\i<0是FALSE,其中i=32 /*与GCC6 !!*/的结果很奇怪。
然而,对于GCC4,我得到了:
i > 31 \x\i<0是true,其中i=32 /*的结果与GCC4 */一致。
看起来很好。
,这怎么可能??
代码片段(损坏的遗留代码!):
static int check_params(... input parameters ...) {
/* Note that value can be 0 (zero) */
uint32_t value = ....
int i;
i = __builtin_ctz(value);
if (i > 31 || i < 0) {
printf("i > 31 || i < 0 is true, where i=%d", i);
/* No 1 found */
return 0;
} else {
printf("i > 31 || i < 0 is FALSE, where i=%d", i);
}
return i;
}根据GCC内建函数文献,必须避免调用__builtin_ctz(0):
内置函数: int __builtin_ctz (无符号int x)返回x中尾随0位数,从最不重要的位位置开始。如果x为0,则结果为未定义的。
因此,显然,编码错误的解决方案是在调用__builtin_ctz( value )之前简单地检查该值。这一点很清楚,也是可以理解的。
我可以停下来,转到其他主题.,但是,我还是不明白我怎么可能(用坏了的代码)得到以下输出:
i > 31 x\i<0是FALSE,其中i=32 /*与GCC6 !!*/的结果很奇怪。
奇怪的GCC6优化什么的?
以防万一:
Cross-compiler: arm-linux-gcc
Architecture: -march=armv7-a有什么想法吗?
发布于 2018-06-15 15:42:36
除非行为不明确,__builtin_ctz总是会返回一个介于0到31之间的数字,GCC知道这一点。因此,check i > 31 || i < 0将始终为false (同样禁止未定义的行为),并且可以进行优化。
如果您查看生成的程序集,您将看到这个条件根本没有出现在代码中(当时的大小写也没有)。
发布于 2018-06-15 15:42:59
未定义的行为并不意味着“值将是任意的”。这意味着编译器可以执行从字面上说,它想要什么。在这种情况下,编译器似乎能够静态地验证,只要value不是0,i总是包含在0到31之间。因此,它甚至不费事地为时间子句生成代码。
你只是幸运的恶魔没从你鼻子里出来。
发布于 2018-06-15 15:45:32
编译器假定未定义的行为不会发生。它可以作出这一假设,因为如果违反限制条件,行为不明确,就有可能产生任何结果,包括不正确的假设所产生的结果。
如果没有未定义的行为,那么i不能是负的或大于31。在此基础上,可以在编译时优化if语句中的条件。
printf实际打印的值无法预测,因此它实际上调用了printf,不管i是什么。在这种情况下,它碰巧是32,但它可能是任何东西。
https://stackoverflow.com/questions/50878726
复制相似问题