1. 程式人生 > >C語言標頭檔案詳解

C語言標頭檔案詳解

1. GCC編譯時問題

在由多個C語言檔案組成的程式中,對於標頭檔案的管理非常重要。標頭檔案提供給使用者一個介面,使用者從中可以知道可以呼叫哪些函式,實現哪些功能,而不必去管這些功能的具體實現。因此,寫好標頭檔案是非常關鍵的。在標頭檔案中,最常見的問題是"標頭檔案的重複包含"。其意思是同一標頭檔案被原始檔包含多次。例如,定義了標頭檔案test1.h和test2.h,其中test2.h包含test1.h,在test3.c中包含了test2.h,那麼會造成test3.c對test1.h包含兩次,導致重複包含問題。如果在test1.h定義了變數,在gcc編譯時就會報"變數重複定義"錯誤。注意:這裡是gcc編譯錯誤。gcc編譯過程和連結過程是不相同的過程。在這裡需要使用下面的巨集進行定義:

#ifndef _TEST1_H_
#define _TEST1_H_
/*標頭檔案內容*/
#endif

解釋: 這三條指令是預處理指令,表示如果沒有定義_TEST1_H_,就定義_TEST1_H_.

為了說明它的作用,以test1.h, test2.h和test3.c為例子,當test3.c包含test1.h和test2.h會出現下面的情形:

#ifndef _TEST1_H_
/*標頭檔案內容*/
#define _TEST1_H_
#endif
#ifndef _TEST1_H_
/*標頭檔案內容*/
#define _TEST1_H_
#endif

第1次,由於沒有定義_TEST1_H_,所以進行定義。當定義_TEST1_H_後,ifndef不會執行。所以,解決了標頭檔案重複包含問題。

注意: (1) 關於_TEST1_H_也可以使用別的名字,沒有規定。一般是在標頭檔案名前加_,後加_,中間的.變成_。因為標頭檔案是唯一的,這樣,能保證唯一性。

          (2)上面幾條語句是預處理命令,在編譯前完成。

          (3) #include關鍵字只是簡單的替換,將標頭檔案替換到原始檔位置。其實,#include 任何檔案    都是合法的。

以上幾條預處理命令能夠保證gcc編譯時出現標頭檔案重複包含導致變數重定義錯誤。


2.  GCC連結時問題

當我們在test1.h定義了全域性變數 int i=10;(這一定是定義,關於“定義”和“宣告”區別以後會介紹)。在test1.c 和 test2.c分別了包含了標頭檔案,test3.c使用test1.c和test2.c的相關函式,當使用下面的命令進行編譯和連結:

 gcc -c  test3.c -o  test3.c  -Wall  //編譯時不會出現“重定義”,ifndef解決此問題

gcc -o  test3 test3.o  test1.o  test2.o  //連結時出現“重定義”,test1.o和test2.o中的i重定義

這是由於在連結過程中,GCC會在全域性範圍內檢查符號,當檢查到test1.o和test2.o都存在符號i,顯然出現了重定義。

因此,在標頭檔案中不要定義(請記住是定義,和宣告區別很大)全域性變數。


3. 總結

(1)標頭檔案重複包含可用ifndef來解決,主要是編譯時報錯,編譯的過程主要是檢查程式碼是否符合C語言基本語法。

(2)如果在標頭檔案定義全域性變數,在連結時可能會出現重複定義錯誤。

(3)建議: 在標頭檔案使用extern宣告變數或函式,在其中一個原始檔進行定義變數或函式,在其它的原始檔使用變數或函式。