函式呼叫時的開銷

2021-08-03 19:29:59 字數 2068 閱讀 8153

問題引入

在學習c語言時,老師強調過呼叫函式時會有開銷,但是函式呼叫的開銷體現在哪幾個方面並不十分清楚!!

舉例說明

寫乙個兩數求和的**,此**中不呼叫函式

#include 

int main()

該程式對應的反彙編如下:

#include 

int main()

00ba1419 pop edi

00ba141a pop esi

00ba141b pop ebx

00ba141c add esp,0e4h

00ba1422 cmp ebp,esp

00ba1424 call __rtc_checkesp (0ba1136h)

00ba1429 mov esp,ebp

00ba142b pop ebp

00ba142c ret

再寫乙個同樣功能的程式,與之前不同的是該函式中有函式呼叫

#include 

int add(int

x, int

y)int main()

該函式對應的反彙編如下所示:

int main()

00051a63 pop edi

00051a64 pop esi

00051a65 pop ebx

00051a66 add esp,0e4h

00051a6c cmp ebp,esp

00051a6e call __rtc_checkesp (051136h)

00051a73 mov esp,ebp

00051a75 pop ebp

00051a76 ret

對比以上兩段**的反彙編,可以發現有如下不同

沒有呼叫函式

c = a + b;

00ba13f3 mov eax,dword ptr [a]

00ba13f6 add eax,dword ptr [b]

00ba13f9 mov dword ptr [c],eax

呼叫函式

c = add(a, b);

00051a33 mov eax,dword ptr [b]

00051a36 push eax

00051a37 mov ecx,dword ptr [a]

00051a3a push ecx

00051a3b call

add (0511dbh)

00051a40 add esp,8

00051a43 mov dword ptr [c],eax

由以上區別可知函式呼叫的開銷在於引數的壓棧過程push、和函式的呼叫call。

幾點說明

由於我測試的環境是vs2013,很可能是編譯器對程式的執行過程進行了優化,一般來說函式的開銷有以下幾個方面:

1、將引數壓入棧中,引數越多,開銷越大

2 、將控制權轉移至函式中

3 、建立新的棧幀,也就是當前函式使用的「一片」棧空間,使用ebp的值來標識新的棧幀,因此要將原棧幀首位址儲存下來,方便回到原來的即呼叫者的棧幀

4 、恢復原棧幀,然後將控制權轉移至呼叫者

函式雖然有一定開銷,但是在該使用函式的時候還是要使用函式,只用當某個函式規模較小並且呼叫的次數比較頻繁時,就將該函式用巨集代替。

額外函式 函式呼叫帶來的額外開銷

在程式設計中,函式 general function 是功能比較單一,使用比較普遍的 塊。如c語言中的printf,scanf就是最常見的函式,它們用於各類資料輸出和輸入,是很常用的的庫函式。所謂函式呼叫,就是使用已經定義好的函式。使用函式能夠避免將相同 重寫多次的麻煩,減少可執行程式的體積,但也會...

函式呼叫時的棧狀態

右側的紅色部分,寫出了引發棧結構變化的對應的指令 棧底方向,高位位址 call somefun 修改esp,棧向下增長,引數入棧,返回值入棧 引數3 引數2 引數1 返回位址 上一層 ebp push ebp 修改esp,棧向下增長 區域性變數1 sub esp 區域性變數占用空間 修改esp,棧向...

列印函式呼叫時間

raii可以實現,通過new delete控制呼叫前後,很懶,只想加幾個字元,不想換行 snippet mlt include define mllog printf ifndef mllog error please define mllog endif struct mlt template m...