預處理器在編譯首遍掃描前執行,處理以 # 開頭的指令:#include、#define、#if 等。合理使用可提升可讀性、可移植性、模組化程度。
#define PI 3.14159
#define MAX(a,b) ((a)>(b)?(a):(b)) // 常見錯誤:缺外層括號
#define SQR(x) ((x)*(x))
規則:
#define TWO_PI 2*PI。printf("PI"); 輸出 "PI"。#undef 終止作用域。
#define MAX(a,b) ((a)>(b)?(a):(b))
#define PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__) // 可變參數 (C99)
關鍵差異:
| 特性 | 宏 | 函式 |
|---|---|---|
| 處理階段 | 預處理(文字替換) | 編譯/連結 |
| 型別檢查 | 無 | 有 |
| 副作用 | 參數多次求值 | 單次求值 |
| 遞迴 | 不支援 | 支援 |
| 除錯 | 難(無符號) | 易(可設中斷點) |
#define SQR(x) x*x
SQR(a+1) // 展開 a+1*a+1 = a+a+1 錯誤
// 正確:
#define SQR(x) ((x)*(x))
#define DISP(expr) printf(#expr " = %d\n", expr)
DISP(x+y); // 輸出 "x+y = 3"
#define MAX (a,b) ... 會被視為無參宏。# 或連接 ## 運算子中特殊處理。#include#include <stdio.h>:系統標準路徑搜尋。#include "my.h":先當前目錄,再系統路徑。#ifndef MY_H#define MY_H...#endif
#if DEBUG
printf("debug: %d\n", x);
#elif TEST
run_tests();
#else
// release
#endif
#define OS_LINUX 1
#define OS_WIN 2
#if TARGET_OS == OS_LINUX
// linux code
#endif
常用:
#ifdef MACRO / #ifndef MACRO、
#if defined(A) && !defined(B)、
#error "message" 強制編譯報錯、
#pragma message("info") 編譯器輸出訊息。
__FILE__、__LINE__、__DATE__、__TIME__、__STDC__、__func__ (C99)。__GNUC__, _MSC_VER 等。const 或 enum 替代宏(有型別、可除錯)。inline 函式(型別安全、單次求值)。#define MUL(a,b) ((a)*(b))。SQR(i++) 會遞增兩次。#ifdef 散落業務邏輯。