自圍堵
現代標題應該是自包含的,這意味著需要使用 header.h
定義的工具的程式可以包含該標題(#include "header.h"
),而不必擔心是否需要首先包含其他標題。
建議:標頭檔案應該是自包含的
歷史規則
從歷史上看,這是一個有點引起爭議的話題。
一個又一個千年, AT&T Indian Hill C 風格和編碼標準規定:
標頭檔案不應巢狀。因此,標頭檔案的序言應描述其他標頭需要
#include
d 才能使標頭正常工作。在極端情況下,如果要將大量標頭檔案包含在多個不同的原始檔中,則可以將所有常用的#include
放在一個包含檔案中。
這是自我遏制的對立面。
現代規則
然而,從那時起,意見傾向於相反的方向。如果原始檔需要使用標頭檔案 header.h
宣告的工具,程式設計師應該能夠寫:
#include "header.h"
並且(僅限於在命令列上設定正確的搜尋路徑),header.h
將包含任何必要的先決條件標頭,而無需向原始檔新增任何其他標頭。
這為原始碼提供了更好的模組化。它還保護源免受在新增此標頭後新增此標頭的原因這一難題,這些難題在程式碼被修改並被黑客攻擊了十年或兩年後出現。
在美國航空航天局戈達德太空飛行中心(GSFC)對於 C 編碼標準是更現代的標準之一 -但現在是有點難以追查。它宣告標題應該是自包含的。它還提供了一種確保標頭自包含的簡單方法:標頭的實現檔案應包含標頭作為第一個標頭。如果它不是自包含的,那麼該程式碼將無法編譯。
GSFC 給出的理由包括:
§2.1.1 標題包括基本原理
該標準要求單元的標題包含單元標題所需的所有其他標題的
#include
語句。首先在單元體中放置單元頭的#include
允許編譯器驗證頭部是否包含所有必需的#include
語句。
本標準不允許的替代設計允許標題中沒有
#include
語句; 所有#includes
都在 body 檔案中完成。然後,單元標頭檔案必須包含#ifdef 語句,以檢查所需的標頭是否包含在正確的順序中。
備用設計的一個優點是正文檔案中的
#include
列表正是 makefile 中所需的依賴列表,編譯器會檢查此列表。使用標準設計,必須使用工具來生成依賴關係列表。但是,所有分支推薦的開發環境都提供了這樣的工具。
備用設計的主要缺點是,如果單元的所需標題列表發生更改,則必須編輯使用該單元的每個檔案以更新
#include
語句列表。此外,編譯器庫單元所需的標頭列表在不同的目標上可能不同。
備用設計的另一個缺點是必須修改編譯器庫頭檔案和其他第三方檔案以新增所需的
#ifdef
語句。
因此,自我遏制意味著:
- 如果標頭檔案
header.h
需要一個新的巢狀標頭檔案extra.h
,則不必檢查每個使用header.h
的原始檔,看看是否需要新增extra.h
。 - 如果標頭檔案
header.h
不再需要包含特定的標頭檔案notneeded.h
,則不必檢查每個使用header.h
的原始檔,看看是否可以安全地刪除notneeded.h
(但請參閱包含你使用的內容) 。 - 你不必為包含先決條件標頭建立正確的順序(這需要拓撲排序才能正確完成工作)。
檢查自我控制
請參閱連結靜態庫以獲取指令碼 chkhdr
,該指令碼可用於測試標頭檔案的冪等性和自包含性。