生活随笔
收集整理的這篇文章主要介紹了
函数调用约定
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
函數調用約定
標簽:? 函數? 調用? 約定?
2008-11-14 15:40
計算機提供了一種被稱為棧的數據結構來支持參數傳遞。
棧是一種先進后出的數據結構,棧有一個存儲區、一個棧頂指針。棧頂指針指向堆棧中第一個可用的數據項(被稱為棧頂)。用戶可以在棧頂上方向棧中加入數據,這個操作被稱為壓棧(Push),壓棧以后,棧頂自動變成新加入數據項的位置,棧頂指針也隨之修改。用戶也可以從堆棧中取走棧頂,稱為彈出棧(pop),彈出棧后,棧頂下的一個元素變成棧頂,棧頂指針隨之修改。
函數調用時,調用者依次把參數壓棧,然后調用函數,函數被調用以后,在堆棧中取得數據,并進行計算。函數計算結束以后,或者調用者、或者函數本身修改堆棧,使堆棧恢復原裝。
在參數傳遞中,有兩個很重要的問題必須得到明確說明:
· 當參數個數多于一個時,按照什么順序把參數壓入堆棧
· 函數調用后,由誰來把堆棧恢復原裝
在高級語言中,通過函數調用約定來說明這兩個問題。常見的調用約定有:
· stdcall
· cdecl
· fastcall
· thiscall C6中的函數調用約定; 調用約定 堆棧清除 參數傳遞 __cdecl 調用者 從右到左,通過堆棧傳遞 __stdcall 函數體 從右到左,通過堆棧傳遞 __fastcall 函數體 從右到左,優先使用寄存器(ECX,EDX),然后使用堆棧 thiscall 函數體 this指針默認通過ECX傳遞,其它參數從右到左入棧
__cdecl是C/C++的默認調用約定; VC的調用約定中并沒有thiscall這個關鍵字,它是類成員函數默認調用約定;
C/C++中的main(或wmain)函數的調用約定必須是__cdecl,不允許更改;
默認調用約定一般能夠通過編譯器設置進行更改,如果你的代碼依賴于調用約定,請明確指出需要使用的調用約定; Delphi6中的函數調用約定; 調用約定 堆棧清除 參數傳遞 register 函數體 從左到右,優先使用寄存器(EAX,EDX,ECX),然后使用堆棧 pascal 函數體 從左到右,通過堆棧傳遞 cdecl 調用者 從右到左,通過堆棧傳遞(與C/C++默認調用約定兼容) stdcall 函數體 從右到左,通過堆棧傳遞(與VC中的__stdcall兼容) safecall 函數體 從右到左,通過堆棧傳遞(同stdcall)
Delphi中的默認調用約定是register,它也是我認為最有效率的一種調用方式,而cdecl是我認為綜合效率最差的一種調用方式;
VC中的__fastcall調用約定一般比register效率稍差一些;
C++Builder6中的函數調用約定; 調用約定 堆棧清除 參數傳遞 __fastcall 函數體 從左到右,優先使用寄存器(EAX,EDX,ECX),然后使用堆棧 (兼容Delphi的register) (register與__fastcall等同) __pascal 函數體 從左到右,通過堆棧傳遞 __cdecl 調用者 從右到左,通過堆棧傳遞(與C/C++默認調用約定兼容) __stdcall 函數體 從右到左,通過堆棧傳遞(與VC中的__stdcall兼容) __msfastcall 函數體 從右到左,優先使用寄存器(ECX,EDX),然后使用堆棧(兼容VC的__fastcall) 常見的函數調用約定中,只有cdecl約定需要調用者來清除堆棧;
C/C++中的函數支持參數數目不定的參數列表,比如printf函數;由于函數體不知道調用者在堆棧中壓入了多少參數,
所以函數體不能方便的知道應該怎樣清除堆棧,那么最好的辦法就是把清除堆棧的責任交給調用者;
這應該就是cdecl調用約定存在的原因吧; VB一般使用的是stdcall調用約定;(ps:有更強的保證嗎)
Windows的API中,一般使用的是stdcall約定;(ps: 有更強的保證嗎)
建議在不同語言間的調用中(如DLL)最好采用stdcall調用約定,因為它在語言間兼容性支持最好;
總結
以上是生活随笔為你收集整理的函数调用约定的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。