在学习过程中,发现一道用汇编解决的C语言问题
#include <stdio.h>
int main() {
int j = 5,num;
num = (++j) + (++j) + (++j);
printf("num = %d\n", num);
return 0;
}
这道题在计算中,我们会认为结果为num = 6+7+8 = 21
在编译完成后发现结果为22
使用反编译工具将a.out反编译为汇编语言后,发现了其中的奥秘
0x400526 <main> push rbp
0x400527 <main+1> mov rbp, rsp
0x40052a <main+4> sub rsp, 0x10
0x40052e <main+8> mov dword ptr [rbp - 8], 5
0x400535 <main+15> add dword ptr [rbp - 8], 1
0x400539 <main+19> add dword ptr [rbp - 8], 1
0x40053d <main+23> mov eax, dword ptr [rbp - 8]
0x400540 <main+26> lea edx, [rax + rax]
0x400543 <main+29> add dword ptr [rbp - 8], 1
0x400547 <main+33> mov eax, dword ptr [rbp - 8]
0x40054a <main+36> add eax, edx
0x40054f <main+41>: mov eax,DWORD PTR [rbp-0x4]
0x400552 <main+44>: mov esi,eax
0x400554 <main+46>: mov edi,0x4005f4
0x400559 <main+51>: mov eax,0x0
0x40055e <main+56>: call 0x400400 <printf@plt>
0x40054f <main+41> mov eax, dword ptr [rbp - 4]
0x400552 <main+44> mov esi, eax
0x400554 <main+46> mov edi, 0x4005f4
0x400559 <main+51> mov eax, 0
0x40055e <main+56> call printf@plt <0x400400>
0x400563 <main+61> mov eax, 0
0x400568 <main+66> leave
0x400569 <main+67> ret
可以看出这里的操作相当于num = 7+7+8 = 22
这个结果是VC6编译器的“习惯”导致的
他编译器背后是怎么运作的呢?通过反编译我们可以看出
j的结果是有三个自增相加,他会优先将前两个自增之后再将他们相加。
然后在把这个结果与最后一个自增结果相加
所以得到的num = 7+7+8 =22
而不是21
相关内容记录
lea对变量没有影响是取地址,对寄存器来说加[]时取值,第二操作数不加[]非法
mov对变量来说没有影响是取值,对寄存器来说是加[]时取地址,第二操作数不加[]是取值