我不得不花一些时间用一个使用三元运算符的代码调试一个奇怪的行为。
给出以下示例程序:
#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)
这可能是一个编译器错误?优化和未优化的代码版本会产生不同的结果。