C 語言預處理器(Preprocessor)在編譯前處理源碼,主要包含:
#define IDENTIFIER string // 範例 #define PI 3.14159 #define MAX(a,b) ((a)>(b)?(a):(b)) // 常見錯誤:缺少外層括號
預處理階段單純字串替換,不計算、不檢查類型。
#define MACRO(params) replacement // 範例 #define INC(x) ((x)+1) y = INC(5); // 展開為 y = ((5)+1);
注意事項:
① 宏名與參數表括號間不能有空格。
② 僅做字串替換,不求值。
③ 函數調用在運行時分配棧幀;宏展開在編譯期,零開銷。
④ 遞歸展開會被阻斷:#define TEST(x) (x + TEST(x)) → 1 + TEST(1)。
| 特性 | 宏 | 函數 |
|---|---|---|
| 展開/調用時機 | 編譯預處理期 | 運行期 |
| 記憶體開銷 | 無(內聯展開) | 棧幀、參數傳遞 |
| 類型檢查 | 無 | 有 |
| 除錯可見性 | 不可見(已展開) | 可見 |
| 適用場景 | 極簡、高頻、型別無關 | 複雜邏輯、需類型安全 |
#include <header.h>:僅在編譯器指定的系統包含目錄搜尋。#include "header.h":優先在當前源文件目錄搜尋,找不到再去系統目錄。專案自定義頭文件用雙引號,標準庫/系統頭文件用尖括號。
#if EXPR // code #elif EXPR2 // code #else // code #endif #ifdef MACRO // MACRO 已定義 #endif #ifndef MACRO // MACRO 未定義 #endif
常見用途:
① 頭文件防重複包含(Guard Macro)
② 不同平台/配置編譯不同代碼
③ 暫時屏蔽代碼片段
__LINE__:當前行號__FILE__:當前文件名__DATE__:編譯日期 "Mmm dd yyyy"__TIME__:編譯時間 "hh:mm:ss"__STDC__:標準 C 模式為 1#define SQUARE(x) x*x 為何錯?→ SQUARE(2+3) 展開為 2+3*2+3=11,正確寫法 ((x)*(x))。\ 換行,末尾不加分號。#(字串化)與 ##(符號連接)運算子用法。#error 強制編譯報錯,#line 修改行號/文件名,#pragma 編譯器指令。assert 實現原理(NDEBUG 控制)。預處理器是 C 語言強大的元編程工具,掌握宏定義陷阱、包含路徑規則、條件編譯技巧,是寫出可移植、可配置、高效代碼的關鍵,也是面試必考核心。