I had to spend some time on debugging a strange behaviour with a code that used the ternary operator.
Given the following sample program:
#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;
}
If this code is compiled without optimization, it produce the following output:
$ 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
If, instead, it is compiled with optimization (-O1
is already sufficient), it produce the following output:
$ 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 the ternary operator is replaced with an if..else
, the optimized code produce the same output of the unoptimized code.
void foo(bool b)
{
if (b)
foo((char)1);
else
foo((char)0);
}
Analyzing the assembler code produced by the compiler (I have tested gcc from 4.8 to 7.0) I can see that the compile optimize the code (char)(b ? 1 : 0)
passing directly the value of b
to the other function.
Without the optimization the int foo(bool b)
function produce the following assembler code:
foo(bool):
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
But with the -O1
optimization, the following assembler code is produced:
foo(bool):
sub rsp, 8
movzx edi, dil
call foo(char)
add rsp, 8
ret
(See https://godbolt.org/g/NNAHzJ)
This could be a compiler bug? Optimized and unoptimized versions of the code produce different results.