i++与++i的区别+汇编分析

这是很多初级C/C++程序员最容易碰到的一个问题

这里来给大家简明摘要的给大家讲解一下:

i++

i++是后递增

有如下语句:

 
 
int i = 0;
printf("%d,",i++);

在打印输出时会发现是0,上面也说了i++是后递增其意思就是在一条指令执行完成之后才会去对i这个变量进行递增

printf("%d",i++);的执行流程如下:

先printf打印i的值,在打印完成之后也就是语句结束时对i进行递增

我们可以做个试验:

int i = 0;
printf("%d,",i++);
printf("%d",i);

打印结果:0,1

也就是证明了上面说的后递增会在语句结束时对变量进行递增

我们来看一下汇编代码(如果没有学过汇编的可以直接跳过这一步骤)

	printf("%d", i++);
00C91C79  mov         eax,dword ptr [i]          
00C91C7F  mov         dword ptr [ebp-1C4h],eax  
00C91C85  mov         ecx,dword ptr [i]  
00C91C8B  add         ecx,1  
00C91C8E  mov         dword ptr [i],ecx  
00C91C94  mov         esi,esp  
00C91C96  mov         edx,dword ptr [ebp-1C4h]  
00C91C9C  push        edx  
00C91C9D  push        0C96858h  
00C91CA2  call        dword ptr ds:[0C9A120h]  
00C91CA8  add         esp,8  
00C91CAB  cmp         esi,esp  
00C91CAD  call        __RTC_CheckEsp (0C9115Eh)  

dword(双字类型四字节) ptr(指针指向地址)

dword ptr [i]指令意思就是指向一个四字节的i地址

mov         eax,dword ptr [i]  

此时将eax寄存器中的值写入到栈低指针-1C4h的地址当中去,

 ebp-1C4h内存地址是用来存放一些临时值的!

mov         dword ptr [ebp-1C4h],eax  

通过mov和ptr指令的作用将位于内存中i的值写入的累加器中(EAX寄存器,ALU运算单元所使用的寄存器)

mov         ecx,dword ptr [i]

最后在对暂存器里的值进行递增1

add         ecx,1  

然后写入到里面去

00C91C8E  mov         dword ptr [i],ecx  

最后这一段代码是调用printf函数的代码并将要打印输出的值传递进去

00C91C96  mov         edx,dword ptr [ebp-1C4h]  
00C91C9C  push        edx  
00C91C9D  push        0C96858h  
00C91CA2  call        dword ptr ds:[0C9A120h]  

我们来分析一下

 mov         edx,dword ptr [ebp-1C4h]  

这行代码的作用是将栈中栈低指针-1C4h的值写入到edx通用寄存器当中,注意此时低指针-1C4h的值是0,在最开始的汇编代码处也说过,在一开始编译器就将i的值写入到该内存中去了:

mov         eax,dword ptr [i]          
mov         dword ptr [ebp-1C4h],eax 
期间该内存值没有任何变化

然后压入新值到栈中

 push        edx  
 push        0C96858h  
调用printf函数并打印edx寄存器的值,每次调用printf,printf函数都会自动从edx寄存器中读取要打印的数据
call        dword ptr ds:[0C9A120h]  

从上面的代码可以的值printf的入口地址位于内存中的0C9A120h当中,所以通过上面几行汇编代码的分析也就得知为什么i++在打印时不是递增后的值了

注意printf每次编译运行时地址都会发生改变,printf函数在编译期间会被链接到文件当中并分配一个新的文件偏移内存映射地址!

下面在说一些最后的几行汇编代码吧

给栈顶指针递增8个字节

add         esp,8  

cmp指令是减法操作,操作之后会设置标志位寄存器所以也就是判断指令,注意进行减法运算后并不会对两个寄存器里的值产生任何影响,结果会存放到通用寄存器当中,并根据通用寄存器的值来设置标志位!

判断变址寄存器与esp地址

cmp         esi,esp  

后面的汇编指令中没有任何判断标志位的指令,所以这里就只是调用一下cmp指令,并没有做任何判断!

call        __RTC_CheckEsp (0C9115Eh)  

__RTC_CheckEsp函数是检查某内存缓冲区是否溢出的

调用此函数检查0C9115Eh内存缓冲区是否溢出!


++i就非常简单了

int i = 0;
printf("%d",++i);

打印结果:1

++i为前递增,也就是先对其进行递增后使用printf打印输出

汇编代码:

013A1CB2  mov         eax,dword ptr [i]  
013A1CB8  add         eax,1  
013A1CBB  mov         dword ptr [i],eax  
013A1CC1  mov         esi,esp  
013A1CC3  mov         ecx,dword ptr [i]  
013A1CC9  push        ecx  
013A1CCA  push        0C96858h
013A1CCF  call        dword ptr ds:[0C9A120h]  
013A1CD5  add         esp,8  
013A1CD8  cmp         esi,esp  
013A1CDA  call        __RTC_CheckEsp (0C9115Eh)  
这两行代码可以看出来,直接将i的值写入到eax寄存器中,并直接递增1,也不写入到ebp-1C4h栈地址中临时存储了
mov         eax,dword ptr [i]  
add         eax,1 

最后直接将i的值写入到ecx寄存器中,并把ecx寄存器的值压入栈,然后调用printf函数打印输出

mov         ecx,dword ptr [i]  
push        ecx  
push        0C96858h
call        dword ptr ds:[0C9A120h]  
从汇编代码可以分析出,++i要快于i++,因为++i无需写入到ebp-1C4h栈地址中存储数据,而是直接对i本身内存地址进行操作!


猜你喜欢

转载自blog.csdn.net/bjbz_cxy/article/details/80226054