Ok, so all started here: Unsigned integer and unsigned char holding same value yet behaving differently why?
I wrote the following application to understand what happens behind the scenes (ie, how the compiler is handling this issue).
#include <stdio.h>
int main()
{
{
unsigned char k=-1;
if(k==-1)
{
puts("uc ok\n");
}
}
{
unsigned int k=-1;
if(k==-1)
{
puts("ui ok");
}
}
}
And while compiling it with GCC like:
gcc -O0 -S -masm=intel h.c
I get the following assembly file:
.file "h.c"
.intel_syntax noprefix
.section .rodata
.LC0:
.string "ui ok"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
sub rsp, 16
mov BYTE PTR [rbp-1], -1
mov DWORD PTR [rbp-8], -1
cmp DWORD PTR [rbp-8], -1
jne .L3
mov edi, OFFSET FLAT:.LC0
call puts
.L3:
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section .note.GNU-stack,"",@progbits
And to my big surprise the first check is NOT EVEN THERE.
But, if I compile the same thing with Microsoft Visual C++ (2010), I get (I have cut off a lot of garbage from this listing, that's why it's not so valid):
00B81780 push ebp
00B81781 mov ebp,esp
00B81783 sub esp,0D8h
00B81789 push ebx
00B8178A push esi
00B8178B push edi
00B8178C lea edi,[ebp-0D8h]
00B81792 mov ecx,36h
00B81797 mov eax,0CCCCCCCCh
00B8179C rep stos dword ptr es:[edi]
00B8179E mov byte ptr [k],0FFh
00B817A2 movzx eax,byte ptr [k]
00B817A6 cmp eax,0FFFFFFFFh
00B817A9 jne wmain+42h (0B817C2h)
00B817AB mov esi,esp
00B817AD push offset string "uc ok\n" (0B857A8h)
00B817B2 call dword ptr [__imp__puts (0B882ACh)]
00B817B8 add esp,4
00B817BB cmp esi,esp
00B817BD call @ILT+435(__RTC_CheckEsp) (0B811B8h)
00B817C2 mov dword ptr [k],0FFFFFFFFh
00B817C9 cmp dword ptr [k],0FFFFFFFFh
00B817CD jne wmain+66h (0B817E6h)
00B817CF mov esi,esp
00B817D1 push offset string "ui ok" (0B857A0h)
00B817D6 call dword ptr [__imp__puts (0B882ACh)]
00B817DC add esp,4
00B817DF cmp esi,esp
00B817E1 call @ILT+435(__RTC_CheckEsp) (0B811B8h)
The question is: Why is this happening? Why does GCC "skip" the first IF and how can I force GCC to not to skip it? Optimizations are disabled, but it seems it still optimizes away something ...
My guess (I'm not a GCC developer) is that it does enough static analysis to prove to itself that the first if
's test is never true.
This shouldn't be too hard, since there is no code between the initialization and the test, there is no way any side-effect or external entity could change the variable.
Just for curiosity, try making the variable static
and/or volatile
to see if anything changes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With