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本身記憶體地址進行操作!