C++/C函數的調用規範

來源:互聯網
上載者:User

先看一個代碼

void myfun(int i, int ii){    cout << i << "    " << ii << endl;}void main(){    int b = 3;    int arr[] = {6,7,8,9,10};    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: {
   3:     int i = 0;
   4:     printf( "%d, %d, %d, %d\n", i++, ++i, i, i++ );
   5:     return 0;
   6: }

     它在Visual C++ 2008的環境下編譯時間,輸出結果為2, 3, 3, 0,在MinGW的GCC環境下編譯運行時,輸出結果則為2, 2, 1, 0。可見不同的編譯器在實現時,對printf函數的參數進棧所作策略和抉擇不同,導致了輸出結果不同。結合上面關於對myfun的調用,發現即便在同一個編譯器中,參數的求值順序有時候也會不同。

     進一步學習,請參考卡http://fairymemory.net/2010/01/02/c語言函數壓棧求值順序/

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.