深入淺出C語言(5)----函數

函數可以分爲普通函數和函數指針所指向的函數兩種,本質上沒有多大的區別。函數名都是地址。
示例1:
void test();
void main()
{
 int addr = (int)test; //這裏可以獲得函數的地址值
 test(); //調用
}

void test()
{
}
編譯器編譯的時候,已經把各個函數名轉化地址值了。所以也就能採取 int addr = (int)test; 來獲取了。 main函數中的test(); 的調用,本質上也是彙編指令跳
到 test地址處去執行代碼。 不過,指令跳轉的地址是一個相對main函數地址值的地址,所以不一定等到(int)test;地址值。由於採用了相對地址,所以整個代碼執行的地址可以改動的。
理論上,對於內存所有的代碼,如果知道其函數的地址,都是可以直接跳到該處執行的。只不過在現代的操作系統中,做了內存保護,一般情況下不充許這樣做。在
windows平臺下,Microsoft也只是開一個接口:遠程線程調用。 就是充許當前程序直接進入目標進程中讀取內存中所有的數據,並函數調用的。

在目前我們所寫的簡單示例程序中,我們都沒有調用任何庫函數的。
在理論上,編譯器所支持的C語言數據類型與函數已經能讓我們實現任何功能了。比如,我們可以自己根據標準C庫函數的說明,去實現自己的庫。
標準庫是怎麼實現的呢?? 大家可以參考一下P.J.Plauger 寫的<The Standard C Library>, 中文翻譯《C標準庫》。此書把平時我們所用的標準庫函數的實現過程
都寫得很清楚,大家可以參考一下里面的優秀寫法。比如,printf(const char *s,…) 中的不定參數的實現方法與原理。標準庫中所涉及到的IO操作有一些是與操作系統的driver有關的。比如文件讀寫之類,這些可以忽略不考慮。

在現代的C編譯器中,各種編譯器所實現標準庫接口是一致的,實現方法可能有差別,但這不妨礙我們編程使用。一般實現了庫函數後,會封裝在一起,比如封成lib庫文件的形式供程序調用。前面也講過,調用任何函數,編譯器都要先看到聲明或定義,所以lib庫需要配上一系列聲明庫函數的頭文件。 頭文件 + lib庫 這才構成編譯器對完整庫的使用的。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章