c和汇编---函数
環境:VC++
作用:
函數是完成特定任務的獨立程序代碼單元
1、創建和使用函數
- 函數原型:聲明函數是什么類型,指明函數的返回值和函數接收的參數類型,函數和變量一樣,有多種類型,任何程序在使用函數之前都要聲明該函數的類型
- 函數調用:表明在此處執行函數,執行到函數調用的語句時,程序會找到該函數的定義并執行其中的內容,執行完返回調用函數繼續執行下一行
- 函數定義:詳細說明函數要干啥
我們看看反匯編:
函數原型:
我們可以看出,函數原型這里沒有生成機器碼,這個是給編譯器看得,告訴編譯器這個函數的返回值和函數接收的參數類型,并在別處查看該函數類型,機器碼是給CPU執行的,所以CPU執行到這里,不會干任何事情
函數調用:
函數調用之前,我們可以看到會先把參數存放到棧里面,也就是a,b的值,然后到00401005地址執行,這個地址有個jmp語句,會跳轉到函數的定義出執行
函數定義:
從上面的程序我們可以看出,函數定義會先把esp存放到棧里面,然后把esp的值給ebp,接著開辟一個40h的棧,然后把ebx、 esi、 edi存放到棧里面,接著在一些連續地址存放0CCCCCCCCh,把這些做好后,再執行函數定義里的語句。
16: return a+b; 004010B8 8B 45 08 mov eax,dword ptr [ebp+8] 004010BB 03 45 0C add eax,dword ptr [ebp+0Ch]我們看看函數的最后
004010BE 5F pop edi 004010BF 5E pop esi 004010C0 5B pop ebx 004010C1 8B E5 mov esp,ebp 004010C3 5D pop ebp 004010C4 C3 ret函數的最后,把函數開始存放這些寄存器的內容又給了他們,ebp的值給esp,ebp恢復函數之前的ebp,接著返回。與函數調用的作用是一樣的
函數的作用只完成特定任務,其他什么都沒變,從函數調用到函數定義,最后返回,看起來是只對了a和b的值進行了操作,其他啥都沒變
總結:
函數原型沒有生成機器碼,告訴編譯器我的參數是那些和返回值是那些,函數調用會把參數先壓入棧,接著執行call到一個地址執行,這個地址有一個jmp命令,會到函數定義出執行,函數定義會先把一些寄存器先壓入棧,然后給一些內存賦值,在最后又會把這些寄存器給彈出,恢復成原值,執行ret命令,返回調用函數繼續執行下一行。
2、傳值和傳址的區別
首先我們要認識幾個小知識
- &運算符:取變量的存儲地址
- *間接運算符:取存儲在指針指向地址上的值,也可以用來聲明指針
- 聲明指針變量:類型 * 變量名,聲明指針變量必須指定指針所指向變量的類型,因為不同變量類型占用不同的存儲空間
傳值:
8: sum1=add1(a,b); //函數調用 0040D786 8B 45 F8 mov eax,dword ptr [ebp-8] 0040D789 50 push eax 0040D78A 8B 4D FC mov ecx,dword ptr [ebp-4] 0040D78D 51 push ecx 0040D78E E8 7C 38 FF FF call @ILT+10(add) (0040100f) 0040D793 83 C4 08 add esp,8 0040D796 89 45 F4 mov dword ptr [ebp-0Ch],eax值傳給eax寄存器,然后入棧
傳址:
10: sum2=add2(&a,&b); //函數調用 0040D7AA 8D 45 F8 lea eax,[ebp-8] 0040D7AD 50 push eax 0040D7AE 8D 4D FC lea ecx,[ebp-4] 0040D7B1 51 push ecx 0040D7B2 E8 5D 38 FF FF call @ILT+15(add2) (00401014) 0040D7B7 83 C4 08 add esp,8 0040D7BA 89 45 F0 mov dword ptr [ebp-10h],eax把地址傳給eax,然后入棧
我們知道傳值不可以修改變量的值,而傳址卻可以,從匯編角度看,我們可以更加的清晰明白,傳值只是將值傳過去了,函數調用是去函數定義處執行,不知道變量在哪里,所以沒辦法修改,傳地址到函數定義時就知道變量的地址在哪里了,所以能修改變量得內容
總結
- 上一篇: 摩尔庄园怎么在头顶聊天
- 下一篇: 一桶花生油多少钱啊?