來源:博客園
發生在預處理階段,純文本替換,**無任何計算、類型檢查、作用域概念**。經過預處理 → 編譯 → 匯編 → 鏈接。
#define PI 3.1415926#define SQUARE(x) ((x)*(x))#define N 2+2
int a = N * N; // 展開為 2+2*2+2 = 8,非預期 16
// 修正:括號包裹整個表達式
#define N (2+2) // (2+2)*(2+2) = 16
#define SQUARE(x) x*x
int y = SQUARE(2+2); // 2+2*2+2 = 8
int z = SQUARE(2+2)/SQUARE(2+2); // (2+2*2+2)/(2+2*2+2) = 8/8*8 = 64 錯誤!
// 修正:參數加括號 + 整體加括號
#define SQUARE(x) ((x)*(x))
// SQUARE(2+2) → ((2+2)*(2+2)) = 16
// SQUARE(2+2)/SQUARE(2+2) → 16/16 = 1 正確
() 包裹() 包裹do { ... } while(0) 包裹| 優勢 | 劣勢 |
|---|---|
| 零函數調用開銷 (內聯展開) | 無類型安全,編譯器不檢查參數類型 |
| 可處理任意類型 (泛型效果) | 調試困難:符號表無宏名,斷點無法命中 |
| 可生成代碼 (元編程) | 副作用風險:參數多次求值 |
| 條件編譯配合靈活 | 命名空間污染:無作用域隔離 |
constexpr double PI = 3.1415926;inline int square(int x) { return x*x; }template T square(T x) { return x*x; } #define TO_STRING(x) #x
TO_STRING(hello) → "hello"
TO_STRING(123) → "123"
#define CONCAT(x, y) x##y
CONCAT(var, 1) → var1
CONCAT("abc", "def") → "abcdef"
#define TO_CHAR(x) #@x
TO_CHAR(a) → 'a'
TO_CHAR(1) → '1'
// 超過 1 字符報錯:error C2015
MAX_BUFFER_SIZEinline 函數或模板#define SAFE_FREE(p) do { free(p); p=NULL; } while(0)SQUARE(i++) 會導致 i 增加兩次#if/#elif/#else/#endif,非 #ifdef 判定宏定義存在性#define 是雙刃劍:用得好是零開銷抽象利器,用不好是難以調試的 Bug 溫床。**牢記「預處理純文本替換、無語義理解」**,嚴守括號法則,優先考慮 constexpr/inline/模板替代,僅在條件編譯、平台適配、極簡內聯等場景堅持使用宏。