我們知道在進行函式呼叫時,有幾種呼叫方法,分為c式,pascal式。在c和c++中c式呼叫是預設的,除非特殊宣告。二者是有區別的,下面我們用例項說明一下:
1. __cdecl :c和c++預設呼叫方式
例子:void input( int &m,int &n);/*相當於void __cdecl input(int &m,int &n);*/
以下是相應的彙編**:
00401068 lea eax,[ebp-8] ;取[ebp-8]位址(ebp-8),存到eax
0040106b push eax ;然後壓棧
0040106c lea ecx,[ebp-4] ;取[ebp-4]位址(ebp-4),存到ecx
0040106f push ecx ;然後壓棧
00401070 call @ilt+5(input) (0040100a);然後呼叫input函式
00401075 add esp,8 ;恢復棧
從以上呼叫input函式的過程可以看出:在呼叫此函式之前,首先壓棧ebp-8,然後壓棧ebp-4,然後呼叫函式input,最後input函式呼叫結束後,利用esp+8恢復棧。由此可見,在c語言呼叫中預設的函式修飾_cdecl,由主呼叫函式進行引數壓棧並且恢復堆疊。
下面看一下:位址ebp-8和ebp-4是什麼?
在vc的view下選debug windows,然後選registers,顯示暫存器變數值,然後在選debug windows下面的memory,輸入ebp-8的值和ebp-4的值(或直接輸入ebp-8和-4),看一下這兩個位址實際儲存的是什麼值,實際上是變數 n 的位址(ebp-8),m的位址(ebp-4),由此可以看出:在主呼叫函式中進行實參的壓棧並且順序是從右到左。另外,由於實參是相應的變數的引用,也證明實際上引用傳遞的是變數的位址(類似指標)。
總結:在c或c++語言呼叫中預設的函式修飾_cdecl,由主呼叫函式進行引數壓棧並且恢復堆疊,實參的壓棧順序是從右到左,最後由主調函式進行堆疊恢復。由於主呼叫函式管理堆疊,所以可以實現變參函式。另外,命名修飾方法是在函式前加乙個下劃線(_).
2. winapi (實際上就是pascal,callback,_stdcall)
例子:void winapi input( int &m,int &n);
看一下相應呼叫的彙編**:
00401068 lea eax,[ebp-8]
0040106b push eax
0040106c lea ecx,[ebp-4]
0040106f push ecx
00401070 call @ilt+5(input) (0040100a)
從以上呼叫input函式的過程可以看出:在呼叫此函式之前,首先壓棧ebp-8,然後壓棧ebp-4,然後呼叫函式input,在呼叫函式input之後,沒有相應的堆疊恢復工作(為其它的函式呼叫,所以我沒有列出)
39: void winapi input( int &m,int &n)
40:
004011cc jmp input+18h (00401128)
61:62: }
004011d1 pop edi
004011d2 pop esi
004011d3 pop ebx
004011d4 add esp,48h
004011d7 cmp ebp,esp
004011d9 call __chkesp (004015b0)
004011de mov esp,ebp
004011e0 pop ebp
004011e1 ret 8
最後,我們看到在函式末尾部分,有ret 8,明顯是恢復堆疊,由於在32位c++中,變數位址為4個位元組(int也為4個位元組),所以彈棧兩個位址即8個位元組。
由此可以看出:在主呼叫函式中負責壓棧,在被呼叫函式中負責恢復堆疊。因此不能實現變參函式,因為被調函式不能事先知道彈棧數量,但在主調函式中是可以做到的,因為引數數量由主調函式確定。
下面再看一下,ebp-8和ebp-4這兩個位址實際儲存的是什麼值,ebp-8位址儲存的是n 的值,ebp -4儲存的是m的值。說明也是從右到左壓棧,進行引數傳遞。
總結:在主呼叫函式中負責壓棧,在被呼叫函式中負責彈出堆疊中的引數,並且負責恢復堆疊。因此不能實現變參函式,引數傳遞是從右到左。另外,命名修飾方法是在函式前加乙個下劃線(_),在函式名後有符號(@),在@後面緊跟引數列表中的引數所佔位元組數(10進製),如:void input(int &m,int &n),被修飾成:_input@8
對於大多數api函式以及視窗訊息處理函式皆用 callback ,所以呼叫前,主調函式會先壓棧,然後api函式自己恢復堆疊。
如:push edx
push edi
push eax
push ebx
call getdlgitemtexta
你可以想一下,這幾個暫存器中存的都是什麼?
Visual C 中呼叫Windows服務初探
這裡把執行緒的優先順序設到最低,這樣不會耗用過多的系統效能。這個執行緒物件使用threadfunc作為執行緒函式,因此將這個執行緒函式補充完整 public static void threadfunc 安裝完後能過系統的服務管理器你就可以看到你的服務了,只要點選啟動就可以把它啟動,把時間向前改乙個...
函式呼叫方式
cdecl 是c declaration的縮寫,表示c語言預設的函式呼叫方法 所有引數從右到左依次入棧,這些引數由呼叫者清除,稱為手動清棧。被呼叫函式不需要求呼叫者傳遞多少引數,呼叫者傳遞過多或者過少的引數,甚至完全不同的引數都不會產生編譯階段的錯誤。stdcall 是standard call的縮...
函式呼叫方式
現代的程式語言的函式竟然有那麼多的呼叫方式。這些東西要完全理解還得通過彙編 才好理解。他們各自有自己的特點 其實這些呼叫方式的差別在主要在一下幾個方面 1.引數處理方式 傳遞順序,訪問 利用盞還是暫存器 2.函式的結尾處理方式 善後處理 如 棧的恢復由誰恢復?函式內恢復 還是呼叫後恢復 以下是理論 ...