函數參數入棧順序
#include
void foo(int x, int y, int z)
{
printf("x = %d at [%X]\n", x, &x);
printf("y = %d at [%X]\n", y, &y);
printf("z = %d at [%X]\n", z, &z);
}
int main(int argc, char *argv[])
{
foo(, , );
return ;
}
運作結果是:
x = 100 at […60]
y = 200 at […64]
z = 300 at […68]
這是由于,C程式棧的記憶體生長方式是往低位址記憶體生長,這也說明為什麼局部變量無法申請太大記憶體,因為棧内容有限。此外,這個例子說明,函數參數的入棧的順序是從右往左的!。參數入棧順序具體的還與編譯器相關,涉及到C語言中調用約定所采用的方式:
C調用約定在傳回前,要作一次堆棧平衡,也就是參數入棧了多少位元組,就要彈出來多少位元組.這樣很安全.
有一點需要注意:stdcall調用約定如果采用了不定參數,即VARARG的話,則和C調用約定一樣,要由調用者來作堆棧平衡.
(1)_stdcall是 Pascal方式清理C方式壓棧,通常用于Win32 Api中,函數采用從右到左的壓棧方式,自己在退出時清空堆棧。VC将函數編譯後會在函數名前面加上下劃線字首,在函數名後加上”@”和參數的位元組數。 int f(void *p) –>> [email protected](在外部彙編語言裡可以用這個名字引用這個函數)在WIN32 API中,隻有少數幾個函數,如wspintf函數是采用C調用約定,其他都是stdcall
(2)C調用約定(即用 __cdecl關鍵字說明)(The C default calling convention)按從右至左的順序壓參數入棧,由調用者把參數彈出棧。對于傳送參數的記憶體棧是由調用者來維護的(正因為如此,實作可變參數 vararg的函數(如printf)隻能使用該調用約定)。另外,在函數名修飾約定方面也有所不同。 _cdecl是C和C++程式的預設調用方式。每一個調用它的函數都包含清空堆棧的代碼,是以産生的可執行檔案大小會比調用_stdcall函數的大。函 數采用從右到左的壓棧方式。VC将函數編譯後會在函數名前面加上下劃線字首。
(3)__fastcall調用的主 要特點就是快,因為它是通過寄存器來傳送參數的(實際上,它用ECX和EDX傳送前兩個雙字(DWORD)或更小的參數,剩下的參數仍舊自右向左壓棧傳 送,被調用的函數在傳回前清理傳送參數的記憶體棧),在函數名修飾約定方面,它和前兩者均不同。__fastcall方式的函數采用寄存器傳遞參數,VC将 函數編譯後會在函數名前面加上”@”字首,在函數名後加上”@”和參數的位元組數。
(4)thiscall僅僅應用于”C++”成員函數。this指針存放于CX/ECX寄存器中,參數從右到左壓。thiscall不是關鍵詞,是以不能被程式員指定。
(5)naked call。 當采用1-4的調用約定時,如果必要的話,進入函數時編譯器會産生代碼來儲存ESI,EDI,EBX,EBP寄存器,退出函數時則産生代碼恢複這些寄存器的内容。
綜上,其實隻有PASCAL調用約定的從左到右入棧的.而且PASCAL不能使用不定參數個數,其參數個數是一定的。
可變參數的實作
支援可變參數的__cdecl調用其實可以了解的。C方式入棧順序從右往左,那麼在棧底的元素就是可變參數的最右邊一個,我們隻需要知道所有明确參數裡的最左邊一個參數在棧中的位置,剩下到棧底的都是可變參數了,反之如果從左往右入棧,則無法知道最右邊的可變參數在棧中的位置。在具體實作中,也可觀察到其中的原理,包括,需要調用者手動清棧。
float averge(int n_values, ...)
{
va_list var_arg;
// 準備通路可變參數
va_start(var_arg, n_values);// 第一個參數是va_list變量的名字,第2個參數是省略号前最後一個有名字的參數
// 取值
for(::)
sum += va_arg(var_arg, int);// 第二個參數是參數的類型
// 完成處理可變參數,手動清棧
va_end(var_arg);
}
結論很簡單:如果支援可變參數的函數,那麼參數進棧的順序幾乎必然是自右向左 的。并且,參數出棧也不能由函數自己完成,而應該由調用者完成。
函數參數計算順序
主要想說明的是,函數的參數壓棧順序和參數計算順序不是一個概念。一個函數帶有多個參數的時,C++語言沒有規定函數調用時實參的求值順序。這個是編譯器自己規定的。
比方說int z = add(++x,x+y);不同編譯器可能産生不同結果。
轉載自: http://blog.csdn.net/weichaohnu/article/details/8798581