標頭檔
標頭檔(英語:Header file),或包含檔案,是個在程式設計時,特別是在C語言和C++中使用的檔案,通常是原始碼的形式,由編譯器在處理另一個原始檔的時候自動包含進來。一般來說,程式設計師通過編譯器指令將標頭檔包含進其他原始檔的開始(或頭部)。
標頭檔一般包含類、子程式、變數和其他識別碼的前置聲明。需要在一個以上原始檔中被聲明的識別碼可以被放在一個標頭檔中,並在需要的地方包含這個標頭檔。
作用
在大多數現代電腦程式語言中,程式可以被分成如子程式的更小的組件,這些組件可以通過許多物理源檔案分發,這些原始檔被單獨編譯。當一個子程式在定義的位置以外的地方被使用時,就需要引入前置聲明和函數原型的概念。例如,一個函數在一個原始檔中有如下定義:
int add(int a, int b)
{
return a + b;
}
在另一個原始檔中參照的時候就可以聲明成這樣(包含函數原型):
int add(int, int);
int triple(int x)
{
return add(x, add(x, x));
}
但是,這個簡單的方法需要程式設計師為add
在兩個地方維護函數聲明,一個是包含函數實現的檔案,以及使用該函數的檔案。如果函數的定義改變了,程式設計師必須要更改散佈在程式中的所有的原型。
標頭檔提供了解決辦法。模組的標頭檔聲明作為模組公共介面一部分的每一個函數、對象以及資料類型。例如,在下面的情況下,標頭檔僅包含add
的聲明。每一個參照了add
的原始檔使用#include
來包含標頭檔:
/* File add.h */
#ifndef ADD_H
#define ADD_H
int add(int, int);
#endif /* ADD_H */
/* File triple.c */
#include "add.h"
int triple(int x)
{
return add(x, add(x, x));
}
這樣就減少了維護的負擔:當定義改變的時候,只須更新聲明的一個獨立副本(在標頭檔中的那個)。在包含對應的定義的原始檔中也可以包含標頭檔,這給了編譯器一個檢查聲明和定義一致性的機會。
/* File add.c */
#include "add.h"
int add(int a, int b)
{
return a + b;
}
通常,標頭檔被用來唯一指定介面,且多少提供一些文件來說明如何使用在該檔案中聲明的組件。在這個例子中,子程式的實現放在一個單獨的原始檔中,這個原始檔被單獨編譯。(在C和C++中有個例外,即行內函數。行內函數通常放在標頭檔中,因為大多數實現如果不知道其定義,在編譯時便無法適當的展開行內函數。)
替代
在訪問聲明在不同檔案中的識別碼問題上,標頭檔不是唯一的解決方法。他們也有缺點,當定義改變的時候可能仍然需要在兩個地方來修改(標頭檔和原始檔)。一些更新的語言(如Java)省略掉了標頭檔,而使用命名方案(naming scheme),這就允許編譯器來定位與介面和類實現相關的原始檔。
#include陳述式的兩種語法
#include
陳述式有兩種方式包含標頭檔,分別是使用雙引號" "
與左右尖括號< >
。其區別是(對於不是使用完全檔案路徑名的)標頭檔的搜尋順序不同:
使用雙引號" "
的標頭檔的搜尋順序:
- 包含該
#include
陳述式的原始檔所在目錄; - 包含該
#include
陳述式的已經打開的標頭檔的逆序(因為標頭檔可以#include
另一個標頭檔構成一個序列); - 編譯選項-I所指定的目錄
- 環境變數INCLUDE所定義的目錄
使用左右尖括號< >
的標頭檔的搜尋順序:
- 編譯選項-I所指定的目錄
- 環境變數INCLUDE所定義的目錄