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

时间:2018-06-15 15:34:12

标签: c gcc undefined-behavior gcc4 gcc6

使用GCC6和下面的代码片段,此测试

if (i > 31 || i < 0) {

false ,执行此printf

printf("i > 31 || i < 0 is FALSE, where i=%d", i);

并产生这个非常奇怪的输出(GCC6):

  

i&gt; 31 ||我&lt; 0 FALSE ,其中 i = 32 / *奇怪的结果与GCC6! * /

而GCC4则得到:

  

i&gt; 31 ||我&lt; 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;
}

根据the documentation about GCC builtin functions,必须避免调用__builtin_ctz(0):

  

内置函数:int __ builtin_ctz (unsigned int x)返回   x中的尾随0位数,从最低有效位开始   位置。如果x为0,结果未定义

很明显,编码错误的解决方案是在调用__builtin_ctz(value)之前简单地检查该值。这很清楚,也很明白。

我可以在那里停下来转移到其他主题...... 但是,我仍然不明白我怎么可能(使用破碎的代码),得到以下输出:

  

i&gt; 31 ||我&lt; 0 FALSE ,其中 i = 32 / *奇怪的结果与GCC6! * /

奇怪的GCC6优化还是什么?

以防万一:

Cross-compiler: arm-linux-gcc
Architecture: -march=armv7-a

有什么想法吗?

4 个答案:

答案 0 :(得分:6)

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

如果查看生成的程序集,您会发现条件根本不会出现在代码中(当时情况也不会出现)。

答案 1 :(得分:3)

未定义的行为并不意味着&#34;该值将是任意的。&#34;这意味着编译器可以执行literally anything it wants to。在这种情况下,看起来编译器能够静态验证只要value不是0 i将始终在0到31之间(包括0和31)。因此,它甚至不会为then子句生成代码。

你只是幸运的恶魔没有从你的鼻子里出来。

另请参阅:Undefined behavior can result in time travelThe premature downcastWhy undefined behavior may call a never-called functionmany many many other discussions of UB此处。

答案 2 :(得分:1)

编译器假定未定义的行为不会发生。它可以做出这样的假设,因为如果违反约束并且行为未定义,任何结果都是可能的,包括错误假设导致的结果。

如果没有未定义的行为,则i不能为负或大于31.在此基础上,if语句中的条件可以在编译时进行优化。

printf实际打印的值无法预测,因此它实际上会调用printf,而i恰好是public void returnMenu(Window windows) { Menu menu = new Menu(); menu.Show(); windows.Hide(); } 。在这种情况下,它恰好是32,但它可能是任何东西。

答案 3 :(得分:0)

C标准指出,实现将未定义行为视为邀请编译器以环境记录的时尚特征行事,并且基本原理指出将行为分类为UB旨在实现高质量的实现当市场需要时,提供超出标准规定的功能。尽管如此,从他们的行为来看,一些编译器供应商认为让编译器寻找巧妙的方法来开发非自由地处理某些案例的自由比在实际中采用明显受约束的行为更有价值(例如有__builtin_ctz( )在做任何CPU做或产生一些任意值之间以非指定方式选择。)

我个人非常怀疑任何“优化”的价值,通过允许编译器执行除了产生值或执行CPU操作以及任何自然后果之外的任何事情都可以促进任何“优化”的价值将接近允许的值程序员假设在CPU本身没有做任何奇怪的事情的平台上,操作将简单地产生具有非副作用的Unspecified结果。尽管如此,gcc的作者似乎认为要求程序员添加额外的源代码以处理可以在没有额外机器代码的情况下处理的情况,这将以某种方式提高“效率”。