先看乙個**
voidvs2008輸出: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);
}
函式的呼叫規範
函式的呼叫規範,也稱為呼叫約定(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沒有辦法知道乙個函式呼叫需要多少個 什麼樣的引數。即計算機不知道怎麼給這個函式傳遞引數,傳遞引數的工作必須由函式呼叫者和函式本身來協調。為此,計算機提供了一種被稱為棧的資料結構來支援引數傳遞。函式呼叫時,呼叫者依次把引數壓棧,然後呼叫函...