五大核心差異對照
| 維度 | 巨集 (#define) | 函數 |
| 代碼長度 | 預處理展開,每次調用複製代碼 → 目標檔變大 | 僅一份代碼,調用跳轉 → 體積小 |
| 執行速度 | 無呼叫開銷 (壓棧/跳轉/返回),**通常較快** | 有函數調用開銷,現代編譯器可內聯優化 |
| 運算子優先級 | **極易出錯**,參數表達式未加括號會改變結合順序 | 參數先求值再傳入,結果可預期 |
| 參數求值次數 | **每次展開重新計算**,副作用重複 (如 MAX(i++, j++) i 增兩次) | **僅計算一次**,副作用單次 |
| 參數類型檢查 | 無類型,僅文字替換,合法即可 (泛型優勢) | 強類型檢查,類型不匹配報錯 |
經典巨集陷阱
#define SQUARE(x) x*x
// SQUARE(3+2) -> 3+2*3+2 = 11 (錯!應為 25)
// 修正: #define SQUARE(x) ((x)*(x))
#define MAX(a,b) ((a)>(b)?(a):(b))
// MAX(i++, j++) -> i 或 j 增加兩次!
// 函數版: inline int max(int a,int b){ return a>b?a:b; } // 安全
最佳實踐
- 常數定義:用
const 或 enum 替代物件巨集。
- 簡單運算:用
inline 函數 (C99) 替代函數巨集,兼具速度與類型安全。
- 必須用巨集:
__FILE__, __LINE__, 字串化 #, 連接 ##, 可變參數 __VA_ARGS__。
- 巨集命名:全大寫 + 括號保護參數與整體
#define MACRO(x) do {...} while(0)。
現代 C 替代方案
// C99 inline 函數
static inline int max(int a, int b) { return a > b ? a : b; }
// C11 _Generic 泛型選擇 (類模板)
#define MAX(x,y) _Generic((x), \
int: max_int, \
double: max_double \
)(x, y)