包括警衛

其他標頭檔案可以包括標頭檔案。因此,包含多個標頭的原始檔(編譯單元)可以間接地多次包含一些標頭。如果多次包含的標頭檔案包含定義,則編譯器(在預處理之後)檢測到違反一個定義規則(例如 2003 C++標準的§3.2),因此發出診斷和編譯失敗。

使用包含警衛可防止多次包含,有時也稱為標題保護或巨集保護。這些是使用前處理器 #define#ifndef#endif 指令實現的。

例如

// Foo.h
#ifndef FOO_H_INCLUDED 
#define FOO_H_INCLUDED

class Foo    //  a class definition
{
};

#endif

使用包含警衛的關鍵優勢在於它們可以與所有符合標準的編譯器和前處理器一起使用。

但是,包含防護也會給開發人員帶來一些問題,因為必須確保巨集在專案中使用的所有頭中都是唯一的。具體來說,如果兩個(或更多)標頭使用 FOO_H_INCLUDED 作為其包含保護,則編譯單元中包含的第一個標頭將有效地防止包含其他標頭。如果專案使用許多第三方庫以及碰巧使用的標頭檔案,則會引入特定的挑戰。

還必須確保包含保護中使用的巨集不與標頭檔案中定義的任何其他巨集衝突。

大多數 C++實現還支援 #pragma once 指令,該指令確保檔案僅在單個編譯中包含一次。這是事實上的標準指令,但它不是任何 ISO C++標準的一部分。例如:

// Foo.h
#pragma once

class Foo
{
};

雖然 #pragma once 避免了與包含守衛相關的一些問題,但是標準中的定義 - 本質上是編譯器特定的鉤子,並且將被不支援它的編譯器默默地忽略。使用 #pragma once 的專案更難以移植到不支援它的編譯器。

C++的許多編碼指南和保證標準特別禁止使用前處理器而不是 #include 標頭檔案或用於在標頭檔案中放置包含保護的目的。