—————————
H檔案和C檔案怎麼用呢?一般來說,H檔案中是declare(聲明),C檔案中是define(定義)。因為C檔案要編譯成庫檔案(Windows下是.obj/.lib,UNIX下是.o/.a),如果別人要使用你的函數,那麼就要引用你的H檔案,所以,H檔案中一般是變數、宏定義、枚舉、結構和函數介面的聲明,就像一個介面說明檔案一樣。而C檔案則是實現細節。
H檔案和C檔案最大的用處就是聲明和實現分開。這個特性應該是公認的了,但我仍然看到有些人喜歡把函數寫在H檔案中,這種習慣很不好。(如果是C++話,對於其模板函數,在VC中只有把實現和聲明都寫在一個檔案中,因為VC不支援export關鍵字)。而且,如果在H檔案中寫上函數的實現,你還得在makefile中把標頭檔的依賴關係也加上去,這個就會讓你的makefile很不規範。
最後,有一個最需要注意的地方就是:帶初始化的全域變數不要放在H檔案中!
例如有一個處理錯誤資訊的結構:
char* errmsg[] = {
/* 0 */ "No error",
/* 1 */ "Open file error",
/* 2 */ "Failed in sending/receiving a message",
/* 3 */ "Bad arguments",
/* 4 */ "Memeroy is not enough",
/* 5 */ "Service is down; try later",
/* 6 */ "Unknow information",
/* 7 */ "A socket operation has failed",
/* 8 */ "Permission denied",
/* 9 */ "Bad configuration file format",
/* 10 */ "Communication time out",
......
......
};
請不要把這個東西放在標頭檔中,因為如果你的這個標頭檔被5個函數庫(.lib或是.a)所用到,於是他就被連結在這5個.lib或.a中,而如果你的一個程式用到了這5個函數庫中的函數,並且這些函數都用到了這個出錯資訊數組。那麼這份資訊將有5個副本存在於你的執行檔案中。如果你的這個errmsg很大的話,而且你用到的函數庫更多的話,你的執行檔案也會變得很大。
正確的寫法應該把它寫到C檔案中,然後在各個需要用到errmsg的C檔案頭上加上 extern char* errmsg[]; 的外部聲明,讓編譯器在連結時才去管他,這樣一來,就只會有一個errmsg存在於執行檔案中,而且,這樣做很利於封裝。
我曾遇到過的最瘋狂的事,就是在我的目標檔案中,這個errmsg一共有112個副本,執行檔案有8M左右。當我把errmsg放到C檔案中,並為一千多個C檔案加上了extern的聲明後,所有的函數庫檔案尺寸都下降了20%左右,而我的執行檔案只有5M了。一下子少了3M啊。
[ 備忘 ]
—————
有朋友對我說,這個只是一個特例,因為,如果errmsg在執行檔案中存在多個副本時,可以加快程式運行速度,理由是errmsg的多個複本會讓系統的記憶體換頁降低,達到效率提升。像我們這裡所說的errmsg只有一份,當某函數要用errmsg時,如果記憶體隔得比較遠,會產生換頁,反而效率不高。
這個說法不無道理,但是一般而言,對於一個比較大的系統,errmsg是比較大的,所以產生副本導致執行檔案尺寸變大,不僅增加了系統裝載時間,也會讓一個程式在記憶體中占更多的頁面。而對於errmsg這樣資料,一般來說,在系統運行時不會經常用到,所以還是產生的記憶體換頁也就不算頻繁。權衡之下,還是只有一份errmsg的效率高。即便是像logmsg這樣頻繁使用的的資料,作業系統的記憶體調度演算法會讓這樣的頻繁使用的頁面常駐於記憶體,所以也就不會出現記憶體換頁問題了。