乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      函數(shù)參數(shù)的壓棧順序

       semo_zhang 2013-12-09

       在CSDN上看到一篇關(guān)于函數(shù)參數(shù)的壓棧順序的帖子,挺有意思,貼出如下:
      網(wǎng)址:http://topic.csdn.net/u/20100216/21/ec98464e-a47e-4263-bb1c-a001e130ba87.html
      設(shè)int arr[]={6,7,8,9,10};
      int *ptr=arr;
      *(ptr++)+=123;
      printf("%d,%d",*ptr,*(++ptr));
      答案為什么是:8,8


      int arr[]={6,7,8,9,10};
      int *ptr=arr;//現(xiàn)在ptr指向6
      *(ptr++)+=123;//現(xiàn)在ptr指向7,第一個元素變?yōu)?29
      printf("%d,%d",*ptr,*(++ptr)); //考慮從右往左計算,先是*(++ptr),現(xiàn)在ptr指向8,然后*ptr也是8,輸出8,8

      2
      這個題考的關(guān)鍵估計就是printf的運算順序
      printf的參數(shù),函數(shù)printf從左往右讀取,那么將會將數(shù)據(jù)從右向左壓入棧中,處理時候是從棧頂開始的,由函數(shù)的調(diào)用者將棧中的參數(shù)彈出棧。

       

      3
      printf("%d,%d",*ptr,*(++ptr));中每個參數(shù)的求值順序是未規(guī)定的,或者說是編譯器相關(guān)的,所以如果本題的編譯器先對參數(shù)* (++ptr)求值,那么++的副作用(即使ptr+=1)就在求值后已經(jīng)產(chǎn)生,之后再對參數(shù)*ptr求值,所用的ptr就是增加之后的ptr.如果這樣,結(jié)果就是8,8
      但是C/C++標準沒有規(guī)定編譯器對參數(shù)求值的順序是從左到右還是從右到左,還是先中間后兩邊,所以這題有可能在某個編譯器上實現(xiàn)為先對參數(shù)*ptr求值,再對參數(shù),*(++ptr)求值,這樣結(jié)果就是7,8
      總之這題結(jié)果是編譯器相關(guān)的
      4
      整理一下函數(shù)調(diào)用約定如下: 
                函數(shù)調(diào)用約定不僅決定了發(fā)生函數(shù)調(diào)用時函數(shù)參數(shù)的入棧順序,還決定了是由調(diào)用者函數(shù)還是被調(diào)用函數(shù)負責清除棧中的參數(shù),還原堆棧。函數(shù)調(diào)用約定有很多方式,除了常見的__cdecl,__fastcall和__stdcall之外,C++的編譯器還支持thiscall方式,不少C/C++編譯器還支持 naked call方式。這么多函數(shù)調(diào)用約定常常令許多程序員很迷惑,到底它們是怎么回事,都是在什么情況下使用呢?下面就分別介紹這幾種函數(shù)調(diào)用約定。


      1.__cdecl

                編譯器的命令行參數(shù)是/Gd。__cdecl方式是C/C++編譯器默認的函數(shù)調(diào)用約定,所有非C++成員函數(shù)和那些沒有用__stdcall或 __fastcall聲明的函數(shù)都默認是__cdecl方式,它使用C函數(shù)調(diào)用方式,函數(shù)參數(shù)按照從右向左的順序入棧,函數(shù)調(diào)用者負責清除棧中的參數(shù),由于每次函數(shù)調(diào)用都要由編譯器產(chǎn)生清除(還原)堆棧的代碼,所以使用__cdecl方式編譯的程序比使用__stdcall方式編譯的程序要大很多,但是 __cdecl調(diào)用方式是由函數(shù)調(diào)用者負責清除棧中的函數(shù)參數(shù),所以這種方式支持可變參數(shù),比如printf和windows的API wsprintf就是__cdecl調(diào)用方式。對于C函數(shù),__cdecl方式的名字修飾約定是在函數(shù)名稱前添加一個下劃線;對于C++函數(shù),除非特別使用extern "C",C++函數(shù)使用不同的名字修飾方式。


      2.__fastcall

                編譯器的命令行參數(shù)是/Gr。__fastcall函數(shù)調(diào)用約定在可能的情況下使用寄存器傳遞參數(shù),通常是前兩個 DWORD類型的參數(shù)或較小的參數(shù)使用ECX和EDX寄存器傳遞,其余參數(shù)按照從右向左的順序入棧,被調(diào)用函數(shù)在返回之前負責清除棧中的參數(shù)。編譯器使用兩個@修飾函數(shù)名字,后跟十進制數(shù)表示的函數(shù)參數(shù)列表大小,例如:@function_name@number。需要注意的是__fastcall函數(shù)調(diào)用約定在不同的編譯器上可能有不同的實現(xiàn),比如16位的編譯器和32位的編譯器,另外,在使用內(nèi)嵌匯編代碼時,還要注意不能和編譯器使用的寄存器有沖突。


      3.__stdcall

      編譯器的命令行參數(shù)是/Gz,__stdcall是Pascal程序的缺省調(diào)用方式,大多數(shù)Windows的API也是__stdcall調(diào)用約定。 __stdcall函數(shù)調(diào)用約定將函數(shù)參數(shù)從右向左入棧,除非使用指針或引用類型的參數(shù),所有參數(shù)采用傳值方式傳遞,由被調(diào)用函數(shù)負責清除棧中的參數(shù)。對于C函數(shù),__stdcall的名稱修飾方式是在函數(shù)名字前添加下劃線,在函數(shù)名字后添加@和函數(shù)參數(shù)的大小,例如:_functionname@number

      4.thiscall

                thiscall只用在C++成員函數(shù)的調(diào)用,函數(shù)參數(shù)按照從右向左的順序入棧,類實例的this指針通過ECX寄存器傳遞。需要注意的是thiscall不是C++的關(guān)鍵字,不能使用thiscall聲明函數(shù),它只能由編譯器使用。

      5.naked call

                  采用前面幾種函數(shù)調(diào)用約定的函數(shù),編譯器會在必要的時候自動在函數(shù)開始添加保存ESI,EDI,EBX,EBP寄存器的代碼,在退出函數(shù)時恢復這些寄存器的內(nèi)容,使用naked call方式聲明的函數(shù)不會添加這樣的代碼,這也就是為什么稱其為naked的原因吧。naked    call不是類型修飾符,故必須和_declspec共同使用。

                  VC的編譯環(huán)境默認是使用__cdecl調(diào)用約定,也可以在編譯環(huán)境的Project Setting...菜單-》C/C++ =》Code    Generation項選擇設(shè)置函數(shù)調(diào)用約定。也可以直接在函數(shù)聲明前添加關(guān)鍵字__stdcall、__cdecl或__fastcall等單獨確定函數(shù)的調(diào)用方式。在Windows系統(tǒng)上開發(fā)軟件常用到WINAPI宏,它可以根據(jù)編譯設(shè)置翻譯成適當?shù)暮瘮?shù)調(diào)用約定,在WIN32中,它被定義為 __stdcall。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多