#define F (x) ((x) - 1) // 定義宏 F,參數列表為空,主體包含 "(x) - 1"
#define F(x) ((x) - 1) // 定義類函數宏 F(x)
第一個定義中 F 後有空格,預處理器視為類對象宏,展開時 F(5) 變為 (x) - 1(5)(語法錯誤)。鐵律:宏名與左括號之間不可有空格。
#define T1 struct type* T1 a,b;
// 展開為:struct type* a, b; // a 是指針,b 是結構體變量!
解決:使用 typedef 而非宏定義類型別名:
typedef struct type* TypePtr;,再聲明 TypePtr a, b; 兩者皆為指針。
#define max(a,b) ((a)>(b)?(a):(b))
int x[3] = {2,3,1};
int biggest = x[0];
int i = 1;
while(i < 3) {
biggest = max(biggest, x[i++]); // 陷阱!
}
展開後:biggest > x[i++] ? biggest : x[i++]。若條件為真,i++ 執行一次;為假,執行兩次!導致 i 增量不確定,邏輯錯誤。
根因:宏參數在展開處被多次求值,帶有副作用(++、--、函數調用)的實參極其危險。
#define MAX(a,b) ({ \
const typeof(a) _a = (a); \
const typeof(b) _b = (b); \
(void)(&_a == &_b); /* 防止未使用警告,確保類型兼容 */ \
_a > _b ? _a : _b; \
})
特性:
1. typeof 推導實參類型,支持任意算術類型。
2. 臨時變量 _a/_b 確保參數僅求值一次。
3. 語句表達式 ({ ... }) 返回最後一條表達式的值。
注意:此為 GCC/Clang 擴展,非標準 C,跨平台項目需謹慎使用或提供回退實現。
// 法一:指針轉換(最常用)
bool is_little_endian() {
int x = 1;
return *(char*)&x == 1; // 低地址存低位 -> 小端
}
// 法二:聯合體(嚴格別名規則友好)
bool is_little_endian_v2() {
union { int i; char c[sizeof(int)]; } u = { .i = 0x11223344 };
return u.c[0] == 0x44; // 低地址為 0x44 -> 小端
}
(int&)a 是 C++ 引用轉換語法,等價於 *(int*)(&a):
1. &a 取變量 a 地址(類型 T*)。
2. (int*) 強制轉為 int*。
3. * 解引用,得到 int 左值。
用途:類型雙關,如通過 int 訪問 float 的位模式。C 中常用聯合體或 memcpy 避免嚴格別名違規。
宏定義威力巨大,但「參數多次求值」、「無類型檢查」、「作用域污染」是三大痛點。現代 C/C++ 應優先使用 inline 函數、constexpr、模板(C++)替代宏;必須用宏時,嚴守:
✅ 參數全括號包裹 ((a))
✅ 宏體用 do{...}while(0) 包裹成語句
✅ 避免副作用實參
✅ 複雜邏輯改用函數