#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; })
#define max(x, y) ({ \
typeof(x) _max1 = (x); \
typeof(y) _max2 = (y); \
(void) (&_max1 == &_max2); \
_max1 > _max2 ? _max1 : _max2; })
({ ... })允許在表達式位置寫入複合語句,最後一條語句的值作為整個表達式的值。使宏能包含變量宣告、多條語句,且可直接參與運算:
int a = min(func1(), func2()); // func1/func2 只會被調用一次
typeof 運算符:編譯期類型推導#define min(x,y) ((x)<(y)?(x):(y)) 的多次求值副作用(如 min(i++, j++) 導致 i/j 增加兩次)。(void) (&_min1 == &_min2):編譯期類型兼容性檢查利用「取兩個變量地址比較」觸發編譯器類型檢查:
x、y 類型不兼容(如 int 與 struct foo),編譯報錯「comparison of distinct pointer types lacks a cast」。signed vs unsigned),僅發出警告,不阻止編譯。(void) 強制丟棄比較結果,避免「statement with no effect」警告。| 維度 | 宏 | 內聯函數 |
|---|---|---|
| 類型泛化 | typeof 自動適配任意類型 | 需 C11 _Generic 或 C++ 模板 |
| 編譯期檢查 | 地址比較技巧實現 | 天然類型安全 |
| 副作用控制 | 單次求值(變量緩存) | 參數預先求值,同樣安全 |
| 調試體驗 | 宏展開難調試 | 可打斷點、查變量 |
| 編碼規範 | 內核歷史慣例,C89 兼容 | 現代 C 推薦 |
Linux 內核堅持 C89 標準,且大量既有代碼依賴宏的泛型特性,故沿用至今。
min(a++, b++) 仍會修改 a、b 各一次,語義可能違背直覺。min(NaN, 1.0) 返回 1.0,符合 IEEE 754 但可能非預期。// C11 _Generic 實現類型泛化內聯函數
#define min(x, y) _Generic((x), \
int: min_int, \
double: min_double, \
default: min_generic)(x, y)
static inline int min_int(int a, int b) { return a < b ? a : b; }
static inline double min_double(double a, double b) { return a < b ? a : b; }
或直接使用 C++ std::min/std::max(模板、類型安全、可調試)。
Linux 內核 min/max 宏是「C 語言元編程」的經典教材:Statement Expression + typeof + 地址比較 三劍合璧,在 C89 約束下實現了類型安全、單次求值、泛型復用。理解其設計哲學,有助於寫出更健壯的系統級代碼。