C C函式的呼叫規範

2022-05-22 20:27:09 字數 1454 閱讀 1915

先看乙個**

void 

myfun(int

i, int

ii)void

main()

; int *ptr = arr;

*(ptr++) += 123;

printf("%d\t%d\n", *ptr, *++ptr);

int

i = 10;

myfun(i, ++i);

}

vs2008輸出:

函式的呼叫規範

函式的呼叫規範,也稱為呼叫約定(calling convention)。函式的呼叫規範決定了函式呼叫時,實參壓棧、退棧及堆疊釋放方式,以及函式名改編(name mangling)的方案,也即命名規範。

windows環境下常用的呼叫規範有:

1)__cdecl:這是c/c++函式預設的呼叫規範,引數從右向左依次傳遞,壓入堆疊,由呼叫函式負責堆疊的清退。這種方式適用於傳遞個數可變的引數給被呼叫函式,因為只有呼叫函式才知道它傳遞了多少個引數給被調函式。如printf函式。

2)__stdcall:引數從右向左依次傳遞,並壓入堆疊,由被呼叫函式清退堆疊。當函式有可變個數引數,自動轉化為__cdecl呼叫規範。

3)__thiscall:這是c++非靜態成員函式的預設呼叫規範,不能使用個數可變的引數。呼叫非靜態成員函式的時候,this指標直接儲存在ecx暫存器中,不入棧。其他方面同__stdcall。

4)__fastcall

凡是介面函式都必須顯示指定其呼叫規範,除非介面函式是類的非靜態成員函式。

關於結果的解釋

據說此題是華為的筆試題。但可能出題者也沒理解此種的奧秘,而只知道結果。關於函式呼叫的引數求值順序,語言實現標準是未定義的。之所以出現如圖所示的結果,不是由函式的呼叫規範決定的(從右向左對引數壓棧),而是由微軟編譯器的具體實現:引數求值按照自右向左順序決定的。函式呼叫壓棧壓入的是表示式的計算後的值,而不是表示式本身。

另外,如果呼叫myfun(i, ++i); 改為myfun(i, i++);。將輸入:11     10

進一步的困惑

1:

int main()

2:
它在visual c++ 2008的環境下編譯時,輸出結果為2, 3, 3, 0,在mingw的gcc環境下編譯執行時,輸出結果則為2, 2, 1, 0。可見不同的編譯器在實現時,對printf函式的引數進棧所作策略和抉擇不同,導致了輸出結果不同。結合上面關於對myfun的呼叫,發現即便在同乙個編譯器中,引數的求值順序有時候也會不同。

進一步學習,請參考卡語言函式壓棧求值順序/

函式呼叫規範

當高階語言函式被編譯成機器碼時,有乙個問題就必須解決 因為cpu沒有辦法知道乙個函式呼叫需要多少個 什麼樣的引數。即計算機不知道怎麼給這個函式傳遞引數,傳遞引數的工作必須由函式呼叫者和函式本身來協調。為此,計算機提供了一種被稱為棧的資料結構來支援引數傳遞。函式呼叫時,呼叫者依次把引數壓棧,然後呼叫函...

函式呼叫規範

當高階語言函式被編譯成機器碼時,有乙個問題就必須解決 因為cpu沒有辦法知道乙個函式呼叫需要多少個 什麼樣的引數。即計算機不知道怎麼給這個函式傳遞引數,傳遞引數的工作必須由函式呼叫者和函式本身來協調。為此,計算機提供了一種被稱為棧的資料結構來支援引數傳遞。函式呼叫時,呼叫者依次把引數壓棧,然後呼叫函...

函式呼叫規範

當高階語言函式被編譯成機器碼時,有乙個問題就必須解決 因為cpu沒有辦法知道乙個函式呼叫需要多少個 什麼樣的引數。即計算機不知道怎麼給這個函式傳遞引數,傳遞引數的工作必須由函式呼叫者和函式本身來協調。為此,計算機提供了一種被稱為棧的資料結構來支援引數傳遞。函式呼叫時,呼叫者依次把引數壓棧,然後呼叫函...