具有内置功能的奇怪GCC6优化

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)

任何的想法?

sep*_*p2k 6

除非未定义的行为,__builtin_ctz将始终返回0到31之间的数字,GCC知道这一点.因此,检查i > 31 || i < 0将始终为假(再次禁止未定义的行为)并且可以进行优化.

如果查看生成的程序集,您将看到条件根本没有出现在代码中(当时也不会出现).

  • @Bludzee您可以使用`-S`选项在GCC中输出汇编.您还可以使用[Godbolt Compiler Explorer](https://godbolt.org/g/7Q6Rvc)快速查看各种编译器在线生成的程序集,而无需安装它们. (2认同)