1. 程式人生 > >C原始檔包含自己的標頭檔案好處

C原始檔包含自己的標頭檔案好處

一般一個我們工程中一個c原始檔要有一個對應的標頭檔案。構成一個功能模組。

包含一個頭檔案功能優點有如下
1、保持定義和宣告的一致性
2、使得編譯能進行

引言:
我們經常在c工程中發現,原始檔中要包含自己的標頭檔案。一直以來,都不知道為什麼這樣做。

以前的認知:
我認為,.c檔案沒有必要包含自己的.h檔案。.h檔案包含.c檔案中對外提供定義的函式和全域性變數的宣告,.h檔案就是.c檔案提供的對外介面檔案。既然.h檔案就是.c檔案提供的對外介面檔案,那麼.c檔案就沒必要包含自己的.h檔案了(.h檔案是對外提供用的,對內又何必再包含進來呢)。
鑑於這樣的理解,我對於工程中.c原始檔包含自己的.h標頭檔案很是不理解,不知道為什麼要這樣做。

現在對此的認知:
但是現在,我知道為什麼要原始檔包含自己的標頭檔案了。
如下,一段書中的原話:
“如果希望讓編譯器檢查宣告的一致性, 一定要把全域性宣告放到標頭檔案中。特別是, 永遠不要把外部模組外部函式的原型(也就是函式宣告)放到.c 檔案中。這樣 通常宣告與定義的一致性不能得到檢查, 而矛盾*的原型(也就是函式宣告)比不用還糟糕。”
注意:外部函式的原型,就是外部函式的宣告。

對這段話的理解:
為什麼:“永遠不要把外部函式的原型放到.c 檔案中”
這個外部函式A指的是B.c檔案之外定義的函式,A函式定義在a.c檔案中;B.c檔案中需要使用外部函式A,就需要先對外部函式A宣告(對外部函式的宣告就是外部函式原型)。對這個外部函式A的宣告,不能放在B.c檔案裡面來實現。 而是放在a.h檔案進行申明。

以例項說明:
1、 假若工程中有2個原始檔a.c和b.c;a.c的標頭檔案為a.h,b.c的標頭檔案為b.h。
2、a.c中定義了一個函式sum。
3、 b.c要引用sum 這個函式。做法是:在b.c中宣告sum這個函式。然後b.c就可以使用sum函數了。
這樣的做法做到了把外部函式sum的宣告放到了b.c中來。然而,這樣的做法很不妥。

不妥的原因:
sum是在a.c中定義的,而宣告是在b.c中,sum函式的定義和宣告不是在同一個檔案中的。定義和宣告不在同一個檔案中,編譯的時候,編譯器就不能對定義和宣告的一致性進行檢查。
這樣,如果sum的定義和宣告不一致,編譯器就無法檢查出來(定義和宣告不在同一個檔案中),那麼編譯的時候不會報錯,但是程式執行的時候就可能會出錯。而這樣的錯誤,查詢起來又不是很容易。
鑑於此,才這樣說:“永遠不要把外部函式的原型放到.c 檔案中”。
對於上面的情況處理辦法是a.c函式提供的對外函式,資料型別定義,全域性變數申明都放在a.h標頭檔案中,同時a.c檔案包含a.h檔案進行定義和宣告的一致性進行檢查。

那如何才能讓編譯器檢查定義和宣告的一致性呢?
前面說,如果把外部函式的原型放到.c 檔案中,編譯器就無法檢查宣告和定義的一致性(宣告和定義不在同一個檔案中)。那麼,要讓編譯器檢查定義和宣告的一致性呢,自然是把定義和宣告放在同一個檔案中,而如何實現把定義和宣告放在同一個檔案裡呢?
答案:原始檔定義的函式,在原始檔對應的標頭檔案中只對外提供的功能函式進行宣告,然後原始檔包含自己的標頭檔案。這樣定義和宣告就放在同一個檔案裡了。同時要使用A函式的B.c檔案只要包含A.h檔案也可以完成定義和宣告的一致性檢查,因為a.c和a.h可以通過一致性檢查,說明a.h檔案內容沒錯,那麼在b.c檔案裡使用A函式,編譯b.c檔案就會根據a.h標頭檔案對A函式呼叫引數進行檢查。自然可以做到定義和宣告一致性檢查。

結論
c原始檔要包含自己的標頭檔案,目的就是讓編譯器檢查定義和宣告的一致性。