C 中的函式 二 有參有返回值的函式

2022-02-10 01:58:02 字數 3919 閱讀 6338

這次研究下c#中的函式(二) 有參有返回值的函式

依然寫乙個小例子,用來測試

跟上乙個例子差不多,區別就是myfunction有二個引數a,b,返回二個數相加的值

f5除錯執行,中斷後轉到反彙編

這裡很明顯看到不同了

這裡就得講到引數傳遞的方式,引數從左向右依次存入暫存器ecx edx

但是不同的程式語言有不同的傳遞引數的方式,有空再寫一篇文章介紹下

要是學過彙編的,到這裡又有疑問了,要是每個實參都儲存在暫存器中,那超過暫存器數量怎麼辦?

有疑惑就得測試,這是一貫原則,好吧再開個工程,寫乙個3個引數的相同函式

轉到反彙編,look一下, 第三個實參是直接壓棧

那如果五個引數呢,再寫乙個函式測試下

到這就很明了了

總結一下: 如果傳遞的實參數量小於2個使用的ecx edx暫存器,如果大於2個引數,

使用堆疊進行傳遞.

ok,明白了引數傳遞的方式回到最開始的例子,進一步分析myfunction函式內部

f10單步執行二次,停在001f2dd5

然後f11進入函式內部檢視

這裡反彙編**太長,就不截圖了,直接貼反彙編**

001f2df8 push ebp         //前面這二句用來儲存esp

001f2df9 mov ebp,esp   //此時ebp指向棧頂

001f2dfb push edi

001f2dfc push esi

001f2dfd push ebx   //對edi esi ebx暫存器壓棧進行儲存

//這裡開始就是我們研究的重點了,可以f10單步執行,順帶檢視暫存器跟堆疊中值

//這裡多出來的10h是返回值位址,二個形參位址,乙個臨時變數sum位址

001f2dfe sub esp,3ch //接合上面那三句,此時esp移動了0xc + 0x3c = 0x48個位元組

001f2e01 mov esi,ecx

//這個ecx 是1, 代表第乙個實參,儲存在esi中

001f2e03 lea edi,[ebp-38h]   // 取位址操作esp + 0x10 = 從棧頂往下第四個位置

001f2e06 mov ecx,0bh           //這三行把0xb* 4 = 44個位元組空間清零

001f2e0b xor eax,eax       

001f2e0d rep stos dword ptr es:[edi]

001f2e0f mov ecx,esi           //把引數1儲存在ecx 

001f2e11 mov dword ptr [ebp-3ch],ecx    // 把引數1儲存在[ebp-0x3c] 處

001f2e14 mov dword ptr [ebp-40h],edx    //把引數2儲存在[ebp-0x40h]處

001f2e17 cmp dword ptr ds:[0018c7a8h],0

001f2e1e je 001f2e25

001f2e20 call 71c6cb2d

001f2e25 xor edx,edx

001f2e27 mov dword ptr [ebp-48h],edx

001f2e2a xor edx,edx

001f2e2c mov dword ptr [ebp-44h],edx

001f2e2f nop

//這裡就是具體計算的地方

22: int sum = a + b;

001f2e30 mov eax,dword ptr [ebp-3ch] //把第乙個引數儲存在eax中

001f2e33 add eax,dword ptr [ebp-40h]  //然後通過add把eax + 第二個引數,結果就是1 + 2 = 3

001f2e36 mov dword ptr [ebp-44h],eax  //然後把相加的結果放在臨時變數中

001f2e39 mov eax,dword ptr [ebp-44h]  //又從臨時變數中取出結果放在eax(這句完全多餘)

001f2e3c mov dword ptr [ebp-48h],eax  //把結果放在返回值位址中. 有返回值情況下eax儲存的都是返回值

//這是當前堆疊中的情況

//這後面的**是當前函式返回時必須要做的堆疊平衡處理 

001f2e3f nop

001f2e40 jmp 001f2e42

001f2e42 mov eax,dword ptr [ebp-48h]

001f2e45 lea esp,[ebp-0ch]

001f2e48 pop ebx

001f2e49 pop esi

001f2e4a pop edi

001f2e4b pop ebp

001f2e4c ret

多於二個引數時,也順帶看一下核心**

前面說過,多餘二個引數時,前二個引數儲存在暫存器ecx edx中,後面的引數儲存在堆疊中

18: int sum = a + b + c + d;

001a34b0 mov eax,dword ptr [ebp-3ch]    //eax = 第乙個引數

001a34b3 add eax,dword ptr [ebp-40h]    //eax = eax + 第二個引數

001a34b6 add eax,dword ptr [ebp+0ch]   //eax += 第三個引數 直接從堆疊中取不需要再開闢棧空間

001a34b9 add eax,dword ptr [ebp+8]       //eax += 第四個引數 直接從堆疊中取不需要再開闢棧空間

001a34bc mov dword ptr [ebp-44h],eax   // 臨時變數sum = 前四個數之和

19: return sum;                          

001a34bf mov eax,dword ptr [ebp-44h]   //把臨時變數sum給eax

001a34c2 mov dword ptr [ebp-48h],eax   //把結果放在返回值位址中. 有返回值情況下eax儲存的都是返回值

001a34c5 nop

001a34c6 jmp 001a34c8

有返回值的函式呼叫

有返回值的sql儲存過程 sqlconnection sqlconn new sqlconnection conn sqlcommand cmd new sqlcommand cmd connection sqlconn cmd commandtext categoriestest3 cmd com...

建構函式有返回值

function f1 console.log new f1 返回例項,委託原型 console.log new f1 name f1 console.log f1 name uncaught typeerror cannot read property name of undefined cons...

有返回值和無返回值函式

前面在定義函式時,有些函式使用了return語句,有些函式沒有使用return語句,使用return語句與不使用return語句有什麼區別呢?由前面的章節我們知道,若定義函式時沒有使用return語句,則預設返回乙個none。要返回乙個none,可以只寫乙個return,但要返回具體的數值,就需要在...