標頭檔開頭常見的三行巨集:
#ifndef _MYHEADER_H_
#define _MYHEADER_H_
// 標頭檔內容
#endif
被稱為Include Guard(防重複包含守衛)。本文深入解析其必要性、運作原理、命名慣例、巢狀包含陷阱與變數定義禁忌。
當多個 .c/.cpp 檔案包含相同標頭檔,且一起編譯連結時,會發生重複定義錯誤。
a.cpp → b.h → d.h (定義 class D) ↘ c.h → d.h (再次定義 class D) → 編譯錯誤:redefinition of 'class D'
編譯器處理 a.cpp 時,會依序展開 b.h、d.h、c.h、d.h,導致 d.h 內容被編譯兩次。
_MYHEADER_H_ 未定義 → 進入區塊 → 定義巨集 → 編譯內容#ifndef 判斷為假 → 直接跳至 #endif → 內容略過檔案名:stdio.h → 巨集:_STDIO_H_ 檔案名:my_lib.h → 巨集:_MY_LIB_H_ 檔案名:foo/bar.h → 巨集:_FOO_BAR_H_
/、\、. 統一替換為 ___ 降低衝突機率// 錯誤示範
#ifndef _TEST_H_
#define _TEST_H_
int global_var = 10; // 定義(配置儲存空間)
#endif
後果:
// test.h
#ifndef _TEST_H_
#define _TEST_H_
extern int global_var; // 僅宣告
#endif
// test.c
#include "test.h"
int global_var = 10; // 唯一定義
// test.h
#pragma once
// 內容...
#pragma onceextern、函數原型、類別定義、型別別名).c/.cppusing namespace 汙染全域命名空間遵循上述原則,可從根源消除重複定義錯誤,提升專案編譯穩定性與可維護性。