#define MACRO_NAME(param-list) replacement-text
#define MAX(a,b) ✓;#define MAX (a,b) ✗(視為無參宏,替換文本為 (a,b))。#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define SQUARE(x) ((x)*(x))
int m = MAX(3+2, 10); // 展開:((3+2) > (10) ? (3+2) : (10)) -> 10
int s = SQUARE(a+1); // 展開:((a+1)*(a+1))
(a) 防止 SQUARE(a+1) 展開為 a+1*a+1。((a)>(b)?(a):(b)) 防止 160/SQUARE(a+1) 優先級錯誤。do { ... } while(0) 包裹(見下)。// 1. 無括號
#define SQ(y) y*y
// 2. 參數括
#define SQ(y) (y)*(y)
// 3. 整體括
#define SQ(y) ((y)*(y))
// 4. 終極安全(參數括+整體括)
#define SQ(y) (((y)*(y)))
問題:多語句宏若不加大括號,用在 if 後會出錯。
// 錯誤寫法
#define SAFE_FREE(p) free(p); p = NULL;
if (ptr) SAFE_FREE(ptr); // 僅 free(ptr) 受 if 控制,p=NULL 無條件執行
// 正確寫法
#define SAFE_FREE(p) do { free(p); p = NULL; } while(0)
if (ptr) SAFE_FREE(ptr); // 整個 do-while 視為單一語句
原理:do { ... } while(0) 執行一次,無循環語義,語法上是單一語句,末尾需加分號,完美融入控制流。
#define SQ_MACRO(y) ((y)*(y))
int sq_func(int y) { return y*y; }
int i = 1;
printf("%d ", SQ_MACRO(i++)); // (1)*(2) = 2, i 變 3
printf("%d ", sq_func(i++)); // 3*3 = 9, i 變 4
#define MAX_MACRO(a,b) ((a)>(b)?(a):(b))
int max_func(int a, int b) { return a>b?a:b; }
double x = 3.14, y = 2.71;
MAX_MACRO(x, y); // 返回 double,但比較邏輯可能不精確
max_func(x, y); // 隱式轉 int,丟失精度 -> 編譯器警告
宏「類型無關」看似靈活,實則隱患;函數強制類型檢查更安全。
#define VERSION "1.2.3"。#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof((arr)[0]))。#define SWAP(a,b) do{typeof(a) t=a; a=b; b=t;}while(0)(GNU 擴展)。#ifdef DEBUG #define LOG(...) printf(__VA_ARGS__) #else #define LOG(...) #endif。帶參宏是帶參數的文本模板。牢記「宏名緊貼括號、參數必括、整體必括、多句用 do-while(0)」,並時刻警惕副作用多次求值與無類型檢查。現代 C(C99/C11)推薦:static inline 函數替代宏,const/enum 替代常量宏,_Generic 實現類型泛型——唯有條件編譯仍屬宏專屬領域。