自圍堵

現代標題應該是自包含的,這意味著需要使用 header.h 定義的工具的程式可以包含該標題(#include "header.h"),而不必擔心是否需要首先包含其他標題。

建議:標頭檔案應該是自包含的

歷史規則

從歷史上看,這是一個有點引起爭議的話題。

一個又一個千年, AT&T Indian Hill C 風格和編碼標準規定:

標頭檔案不應巢狀。因此,標頭檔案的序言應描述其他標頭需要 #included 才能使標頭正常工作。在極端情況下,如果要將大量標頭檔案包含在多個不同的原始檔中,則可以將所有常用的 #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,該指令碼可用於測試標頭檔案的冪等性和自包含性。