Reputation: 19150
Consider a piece of C++ code:
int main()
{
volatile int a=0;
if(!a)
++a;
}
I compile it on amd64 system with
g++ (Ubuntu 4.8.1-2ubuntu1~12.04) with command g++ test.cpp -S -o test.S -masm=intel
and get the following code:
...
mov eax, DWORD PTR [ebp-4]
test eax, eax
sete al
test al, al
je .L2
mov eax, DWORD PTR [ebp-4] ; don't use result of sete
add eax, 1
mov DWORD PTR [ebp-4], eax
.L2:
mov eax, 0 ; also drop result of sete
...
This code really surprises me. At first I thought it has something to do with 64-bit mode. But when I tried to compile with -m32
, this bit remained the same.
Why does it check eax
for being zero and then recheck the result once more after setting al
to ZF
? Why doesn't it just do test eax,eax\n jne .L2
?
Upvotes: 3
Views: 155
Reputation: 137547
I think it has to do with how bool
is handled differently in C and C++. In your code, the if(!a)
first converts a
to a bool
(that's what the test eax, eax; sete al
does), and then tests that boolean (in al
) for true/false.
If you rename as .c
and compile the same code with gcc
, it generates the expected code
mov DWORD PTR [rbp-4], 0
mov eax, DWORD PTR [rbp-4]
test eax, eax
jne .L3
mov eax, DWORD PTR [rbp-4]
add eax, 1
mov DWORD PTR [rbp-4], eax
.L3:
In C, it seems that boolean tests of integral variables happens without the intermediate conversion to bool
. Note that al
is never involved, so this implies that the value is never "converted" to a one-byte bool
before testing it for non-zero.
Upvotes: 6