1.5 函數的調用機制
接下來,我們繼續介紹程序的流程。哪怕是高級語言編寫的程序,函數調用處理也是通過把程序計數器的值設定成函數的存儲地址來實現的。不過,這和條件分支、循環的機制有所不同,因為單純的跳轉指令無法實現函數的調用。函數的調用需要在完成函數內部的處理后,處理流程再返回到函數調用點(函數調用指令的下一個地址)。因此,如果只是跳轉到函數的入口地址,處理流程就不知道應該返回至哪里了。
圖1-7是給變量a和b分別代入123和456后,將其賦值給參數(parameter)來調用MyFunc函數的C語言程序。圖中的地址是將C語言編譯成機器語言后運行時的地址。由于1行C語言程序在編譯后通常會變成多行的機器語言,所以圖中的地址是離散的。

圖1-7 程序調用函數示例(這里直接展示了C語言的源代碼,實際上各地址存儲的應該是變換成機器語言后的程序)
此外,通過跳轉指令把程序計數器的值設定成0260也可實現調用MyFunc函數。函數的調用原點(0132地址)和被調用函數(0260地址)之間的數據傳遞,可以通過內存或寄存器來實現。不過,當函數處理進行到最后的0354地址時,我們知道應該將程序計數器的值設定成函數調用后要執行的0154地址,但實際上這一操作根本無法實現。那么,怎么辦才好呢?
機器語言的call指令和return指令能夠解決這個問題。建議大家把二者結合起來來記憶。函數調用使用的是call指令,而不是跳轉指令。在將函數的入口地址設定到程序計數器之前,call指令會把調用函數后要執行的指令地址存儲在名為棧的主存內。函數處理完畢后,再通過函數的出口來執行return命令。return命令的功能是把保存在棧中的地址設定到程序計數器中。如圖1-7所示,MyFunc函數被調用之前,0154地址保存在棧中。MyFunc函數的處理完畢后,棧中的0154地址就會被讀取出來,然后再被設定到程序計數器中(圖1-8)。

圖1-8 函數調用中程序計數器和棧的職能
在編譯高級編程語言的程序后,函數調用的處理會轉換成call指令,函數結束的處理則會轉換成return指令。這樣一來,程序的運行也就變得非常流暢。
- 深入淺出Prometheus:原理、應用、源碼與拓展詳解
- Learning ASP.NET Core 2.0
- 信息安全技術
- 高級C/C++編譯技術(典藏版)
- Raspberry Pi 2 Server Essentials
- Spring實戰(第5版)
- PhpStorm Cookbook
- Android Native Development Kit Cookbook
- ASP.NET程序開發范例寶典
- 數據分析與挖掘算法:Python實戰
- 視窗軟件設計和開發自動化:可視化D++語言
- Drupal 8 Development:Beginner's Guide(Second Edition)
- 精通Rust(第2版)
- HTML 5與CSS 3權威指南(第4版·上冊)
- Python網絡運維自動化