c/c++中的都是從右往左入棧的,在呼叫函式時,若引數需要運算則先運算,然**棧,再呼叫函式。
程式中棧頂在低位,棧低在高位。
程式入棧順序:
void
push
(int a,
int b,
int c)
先入棧的在棧底,應該儲存在高位;**棧的在棧頂,應該儲存在低位。
位置順序:c > b > a
所以:c最先入棧,a最**棧
函式呼叫是從右往左入棧的
函式引數有運算,則先計算完引數中的全部運算再執行函式
函式引數有運算需要區分是呼叫前執行還是呼叫後執行的函式(++i,i++)
入棧的是臨時變數還是實際變數
分析下面**的運算結果:
int
main()
也可從編譯後的彙編**中看出:
# printf("%d,%d\n", ++i, ++i);
# 取出i的值到暫存器
mov eax, dword ptr _i$[ebp]
# 暫存器自增1
add eax, 1
# 寫回到i
mov dword ptr _i$[ebp], eax
# 取出i的值到暫存器
mov ecx, dword ptr _i$[ebp]
# 暫存器自增1
add ecx, 1
# 寫回到i
mov dword ptr _i$[ebp], ecx
# 讀取i的值到寄存
mov edx, dword ptr _i$[ebp]
# 入棧
push edx
# 讀取i的值到寄存
mov eax, dword ptr _i$[ebp]
# 入棧
push eax
push offset $sg3750
# 呼叫_printf
call _printf
# printf("%d,%d\n", ++i, i++);
# 取出i的值
mov ecx, dword ptr _i$[ebp]
# 儲存到臨時變數
mov dword ptr tv71[ebp], ecx
# 取出i的值,並自增1,寫回i
mov edx, dword ptr _i$[ebp]
add edx, 1
mov dword ptr _i$[ebp], edx
# 取出臨時變數的值,併入棧
mov eax, dword ptr tv71[ebp]
push eax
mov ecx, dword ptr _i$[ebp]
push ecx
push offset $sg3751
call _printf
再思考一下下面的**執行結果:
#include
void
push
(int a,
int b,
int c)
intmain()
很多答案都提到是為了函式可以使用動態引數。
動態引數是如何實現的?
函式是通過棧傳入引數的,動態引數需要壓入個數和型別都未知的引數到棧中。而我們知道第乙個引數一定是最後乙個入棧的,在其他引數之上。
如何讀取動態引數?
引數肯定在棧裡,但是要如何讀取到棧中的引數呢?
熟悉彙編的可能會考慮通過esp暫存器,因為esp指向棧頂位置。但是在函式內,第乙個引數一定不是在棧頂位置:
如果沒有在函式最開始就獲取第乙個引數的位址,在程式執行中esp還可能會變,所以通過esp獲取乙個引數的位置是不可取的,而且不同的編譯器實現還不一定都一樣。
// 通過esp讀取引數值
void
push
(int a,
int b,
int c)
printf
("a = %d\r\n"
, i1)
;printf
("a = %d, ptr = 0x%x\r\n"
, a,
&a);
printf
("b = %d, ptr = 0x%x\r\n"
, b,
&b);
printf
("c = %d, ptr = 0x%x\r\n"
, c,
&c);
}
通過上面的分析,要實現動態引數,我們需要有乙個確切位址的引數,用來定位其他引數。所以在c++的實現中,帶有動態引數的函式,第乙個引數一定是個很明確的引數。
而且引數從右往左入棧,第乙個引數位置就非常明確,且可以快速定位第乙個引數的位置(esp+12)。
結論:引數從右往左入棧可以快速確定第乙個引數的位置,非常適合帶動態引數的函式
從左往右入參可以快速定位最後乙個引數的位置;但如果是動態引數,則無法定位最後乙個引數的位置(型別不確定,無法明確引數size)
動態引數的缺陷:
無法確定引數長度
無法確定引數型別
printf是通過格式化來確定輸出的引數長度和型別。
在寫dll時經常會用stdcall、cdecl宣告函式,為什麼要這樣?其實就是宣告函式引數的傳遞及銷毀方式。
他們之間的區別:
類的成員函式和非成員函式及普通函式在編譯後都是一樣的,類成員函式特殊的地方在於函式呼叫時會通過暫存器(ecx)傳遞this指標。
C C 語言函式中引數的入棧順序
對於函式,之前認為會用就行了,對其中的原理並不是很了解,就比如函式中引數的入棧順序 在這說明一下,函式的引數是儲存在棧中的,還有一些區域性變數也是存放在棧中 這個問題 於某網際網路的面試題,當然答得很不好,查了很多大牛的部落格做一下總結。include using namespace std voi...
合法入棧順序
題目描述 我們知道,乙個入棧序列是的合法出棧序列有,等,而是不合法的.現在冰語有乙個長度為n的序列a 保證序列內數字唯一,且1 a i n 他想知道這個序列是不是入棧順序的合法出棧序列,你能告訴他麼?輸入 第一行為t,表示樣例個數 每個樣例第一行為n,第二行為n個數 1 t 1e4,3 n 100 ...
出棧入棧順序問題
不定項選擇題 依次讀入資料元素序列入棧,每進乙個元素,機器可要求下乙個元素入棧或彈棧,如此進行,則棧空時彈出的元素構成的序列是以下 序列?牛客444334號 ada 可行步驟 a入棧,b入棧,c入棧,d入棧,d出棧,e入棧,e出棧,c出棧,f入棧,f出棧,b出棧,g入棧,g出棧,a出棧 b 不可行,...