自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

函數(shù)調(diào)用的三種約定,你都清楚嗎

開發(fā) 后端
三種調(diào)用方式的區(qū)別相信大家應該有些了解,這篇文章主要從實例和匯編的角度闡述這些區(qū)別的表現(xiàn)形態(tài),使其對它們的區(qū)別認識從理論向?qū)嶋H過渡。

 __cdecl、__stdcall、__fastcall是C/C++里中經(jīng)常見到的三種函數(shù)調(diào)用方式。其中__cdecl是C/C++默認的調(diào)用方式,__stdcall是windows API函數(shù)的調(diào)用方式,只不過我們在頭文件里查看這些API的聲明的時候是用了WINAPI的宏進行代替了,而這個宏其實就是__stdcall了。

三種調(diào)用方式的區(qū)別相信大家應該有些了解,這篇文章主要從實例和匯編的角度闡述這些區(qū)別的表現(xiàn)形態(tài),使其對它們的區(qū)別認識從理論向?qū)嶋H過渡。

我們知道,函數(shù)的調(diào)用過程是通過函數(shù)棧幀的不斷變化實現(xiàn)的:

函數(shù)的調(diào)用,涉及參數(shù)傳遞,返回值傳遞,調(diào)用后返回,這都是通過棧的變化來實現(xiàn)的,對于三種調(diào)用約定而言:

__cdecl:

C/C++默認方式,參數(shù)從右向左入棧,主調(diào)函數(shù)負責棧平衡。

__stdcall:

windows API默認方式,參數(shù)從右向左入棧,被調(diào)函數(shù)負責棧平衡。

__fastcall:

快速調(diào)用方式。所謂快速,這種方式選擇將參數(shù)優(yōu)先從寄存器傳入(ECX和EDX),剩下的參數(shù)再從右向左從棧傳入。因為棧是位于內(nèi)存的區(qū)域,而寄存器位于CPU內(nèi),故存取方式快于內(nèi)存,故其名曰“__fastcall”。

下面從實例來認識一下這三種調(diào)用約定。先來看一個簡單的不能再簡單的程序了:

 

三個函數(shù)的內(nèi)容都是一樣的,不同的是使用了三種調(diào)用的方式。我們先來看看在main函數(shù)調(diào)用三個函數(shù)的時候的匯編代碼: 

按照上面說的那樣,__cdecl按照參數(shù)從右向左的方式進入棧區(qū),注意Fun1()和Fun3()的區(qū)別,F(xiàn)un1()在call Fun1()之后執(zhí)行了add esp,8。這一操作正是我們前面所說的進行棧的平衡。調(diào)用函數(shù)之前連續(xù)進行了兩次push操作將函數(shù)所需的實參5和2先后壓入了棧區(qū),調(diào)用完成后,我們需要恢復調(diào)用前的狀態(tài),則需調(diào)整棧頂指針esp的位置,這一工作由誰來完成就決定了兩種函數(shù)調(diào)用方式__cdecl(主調(diào)函數(shù)完成)和__stdcall(被調(diào)函數(shù)完成)的區(qū)別。上圖我們看到了__cdecl中由主調(diào)函數(shù)完成了,那么__stdcall呢,在被調(diào)函數(shù)Fun3()中,轉(zhuǎn)向被調(diào)函數(shù)結(jié)尾處的代碼,我們看到了這一句:

那么Fun1()結(jié)尾處又是如何呢?

看到了吧,這個ret指令后面跟沒跟值就決定了函數(shù)返回是棧指針ESP需要增加的量。這樣,不需要主調(diào)函數(shù)再調(diào)用add指令為ESP操作平衡棧區(qū),節(jié)約了程序的開銷,一條指令開銷小,如果十萬百萬個這樣的調(diào)用,這個開銷就明顯了。

說完了__cdecl和__stdcall,再來看看__fastcall,如前面圖看到的調(diào)用時并未使用push指令向棧里傳參數(shù),而是使用了

  mov  edx, 5

  mov  ecx, 2

兩條指令。這樣直接將參數(shù)傳入寄存器,被調(diào)函數(shù)在執(zhí)行的時候直接從寄存器取值即可,省去了從棧里取出來給寄存器,再從寄存器取出來放入內(nèi)存。

不過,說個題外話,ecx寄存器經(jīng)常作為計數(shù)和C++里this指針的傳遞媒介。在這種情況下,情況又是怎樣的呢,下次分析C++操作符 new 的時候再予以討論。ecx做計數(shù)器時,需要將ecx中存儲的實參先壓入棧區(qū),計數(shù)操作完成后再pop出來。如此一來,這個fastcall倒顯得不那么fast了。

當然,上面所說的這些操作都是由編譯器在背后為我們完成的,開發(fā)人員無需關(guān)心這些操作,對我們是透明的。不過,知其然更知其所以然方能立于不敗之地! 

 

責任編輯:龐桂玉 來源: C語言與C++編程
相關(guān)推薦

2019-05-08 10:50:37

交換機組網(wǎng)網(wǎng)絡(luò)

2021-09-13 13:05:05

Redis數(shù)據(jù)庫內(nèi)存

2023-02-27 23:45:09

MySQL索引存儲

2023-08-04 08:25:03

客戶配置Spring

2023-09-22 08:01:10

2023-09-14 23:14:57

MySQL索引

2021-02-25 23:40:26

Redis集群架構(gòu)

2023-02-02 14:24:08

物聯(lián)網(wǎng)數(shù)據(jù)分析云平臺

2022-01-10 07:57:25

Linux 插樁Linux 系統(tǒng)

2021-10-10 12:29:27

機器人AI人工智能

2024-05-27 00:20:00

2011-01-18 15:35:59

jQueryJavaScriptweb

2022-07-09 15:37:14

數(shù)字化轉(zhuǎn)型企業(yè)數(shù)字化

2020-09-11 06:39:29

ThreadLocal線程

2024-08-13 08:25:16

C#外部程序方式

2024-04-11 12:57:55

Python函數(shù)

2021-07-10 10:01:37

Python簡單函數(shù)

2021-03-17 09:59:26

Python函數(shù)調(diào)用

2023-03-07 10:32:34

Go語言結(jié)構(gòu)體

2010-02-03 15:46:15

C++函數(shù)傳遞
點贊
收藏

51CTO技術(shù)棧公眾號