三元运算符和优化

时间:2016-12-13 18:36:08

标签: c++ c++11 compiler-optimization ternary-operator

我不得不花一些时间用一个使用三元运算符的代码调试一个奇怪的行为。

给出以下示例程序:

#include <string.h>
#include <stdio.h>

void foo(char c)
{
    printf("%d\n", c);
}

void foo(bool b)
{
    foo((char)(b ? 1 : 0));
}

int main()
{
    for (int i = 0; i < 10; ++i)
    {
        bool b;
        memset(&b, i, 1);
        foo(b);
    }
    return 0;
}

如果在没有优化的情况下编译此代码,则会生成以下输出:

$ g++ -O0 -Wall -Wextra -std=c++11 -o test_bool test_bool.cpp
$ ./test_bool 
0
1
1
1
1
1
1
1
1
1

相反,如果使用优化编译它(-O1已经足够了),它会产生以下输出:

$ g++ -O1 -Wall -Wextra -std=c++11 -o test_bool test_bool.cpp
$ ./test_bool 
0
1
2
3
4
5
6
7
8
9

如果三元运算符替换为if..else,则优化代码将生成未优化代码的相同输出。

void foo(bool b)
{
    if (b)
        foo((char)1);
    else
        foo((char)0);
}

分析编译器生成的汇编代码(我已经测试了gcc从4.8到7.0)我可以看到编译优化代码(char)(b ? 1 : 0)直接将b的值传递给另一个函数。

如果没有优化,int foo(bool b)函数会生成以下汇编代码: FOO(布尔):

foo(bool):
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     eax, edi
        mov     BYTE PTR [rbp-4], al
        cmp     BYTE PTR [rbp-4], 0
        je      .L3
        mov     eax, 1
        jmp     .L4
.L3:
        mov     eax, 0
.L4:
        mov     edi, eax
        call    foo(char)
        nop
        leave
        ret

但是使用-O1优化,会产生以下汇编代码:

foo(bool):
        sub     rsp, 8
        movzx   edi, dil
        call    foo(char)
        add     rsp, 8
        ret

(见https://godbolt.org/g/NNAHzJ

这可能是一个编译器错误?优化和未优化的代码版本会产生不同的结果。

0 个答案:

没有答案