首先看看上面这段C代码,按照C语言的运算符优先级规则,这个程序的运行结果应该是18(首先执行完小括号里的三个++a,这时a就为6,然后在执行加法运算,3个a相加自然等于18)。
可是我在VC6.0下编译这段程序时,如果编译为Debug版,则输出结果为16,如果编译为Release版本,则输出结果为18。
为什么Debug版本的结果会是16呢???怎么想也不应该是16啊。于是自然就想到了看看这段程序对应Debug版的汇编代码吧,看看VC的编译器究竟把这段代码编译成什么样子了。为了简单起见,我只分析子函数bug()。
int a=3,b;
b=(++a)+(++a)+(++a);
以上这两行代码在VC的Debug版本下对应的汇编代码为:
0040102F 8B 45 FC mov eax,dword ptr [ebp-4]
00401032 83 C0 01 add eax,1
00401035 89 45 FC mov dword ptr [ebp-4],eax
00401038 8B 4D FC mov ecx,dword ptr [ebp-4]
0040103B 83 C1 01 add ecx,1
0040103E 89 4D FC mov dword ptr [ebp-4],ecx
00401041 8B 55 FC mov edx,dword ptr [ebp-4]
00401044 03 55 FC add edx,dword ptr [ebp-4]
00401047 8B 45 FC mov eax,dword ptr [ebp-4]
0040104A 83 C0 01 add eax,1
0040104D 89 45 FC mov dword ptr [ebp-4],eax
00401050 03 55 FC add edx,dword ptr [ebp-4]
00401053 89 55 F8 mov dword ptr [ebp-8],edx
上面这段汇编代码的意思,相信只要懂得汇编的朋友都可以很容易看懂,不过为了照顾一下大众,我还是简单说明一下吧,根据变量定义的位置可以知道,ebp-4就是变量a的地址,ebp-8就是变量b的地址,于是以上代码可以简化为:
mov eax,a
add eax,1
mov a,eax
//此时a=4
mov ecx,a
add ecx,1
mov a,ecx
//此时a=5
mov edx,a
add edx,a
//此时edx=10
mov eax,a
add eax,1
mov a,eax
//此时a=6
add edx,a
mov b,edx
//此时b=16
所以,Debug版本的最后输出结果自然就是16,但我认为这是一个错误的结果。但是为什么Release版的又能返回我认为正确的结果18呢?于是,随后我又用OD对Release版的程序进行了逆向分析,大家看图:
这个结果让我感到很意外,在Release版中,子函数bug()居然被优化成了直接返回结果:0x12(十进制就是18)。
至于其中为什么会优化成那样的原因我可就不知道了,这要去问问微软那些开发这个VC编译器(这里顺便提一下:VC6.0自带的 C/C++编译器的版本为:Version 12.00.8804)的工程师了,呵呵。当然也可以通过逆向分析这个VC编译器,从而找到答案,不过本人能力有限,目前还很难办到,若哪位大牛路过,还请不吝赐教。