Blu*_*zee 1 c gcc undefined-behavior gcc4 gcc6
使用GCC6和下面的代码片段,这个测试
if (i > 31 || i < 0) {
Run Code Online (Sandbox Code Playgroud)
是false,执行此printf
printf("i > 31 || i < 0 is FALSE, where i=%d", i);
Run Code Online (Sandbox Code Playgroud)
并产生这个非常奇怪的输出(GCC6):
我> 31 || i <0为FALSE,其中i = 32/*奇怪的结果与GCC6!*/
而对于GCC4,我得到:
我> 31 || i <0为真,其中i = 32/*结果Ok 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;
}
Run Code Online (Sandbox Code Playgroud)
根据有关GCC内置函数的文档,必须避免调用__builtin_ctz(0):
内置函数:int __builtin_ctz(unsigned int x)从最低有效位开始,返回x中的尾随0位数.如果x为0,则结果未定义.
很明显,编码错误的解决方案是在调用__builtin_ctz(value)之前简单地检查该值.这是清楚和明白的.
我可以停在那里并转移到其他主题...... 但是,我仍然不明白我怎么可能(使用破碎的代码),得到以下输出:
我> 31 || i <0为FALSE,其中i = 32/*奇怪的结果与GCC6!*/
奇怪的GCC6优化还是什么?
以防万一:
Cross-compiler: arm-linux-gcc
Architecture: -march=armv7-a
Run Code Online (Sandbox Code Playgroud)
任何的想法?
除非未定义的行为,__builtin_ctz将始终返回0到31之间的数字,GCC知道这一点.因此,检查i > 31 || i < 0将始终为假(再次禁止未定义的行为)并且可以进行优化.
如果查看生成的程序集,您将看到条件根本没有出现在代码中(当时也不会出现).