1. 防止頭文件重複包含
#ifndef COMDEF_H
#define COMDEF_H
// 頭文件內容
#endif
2. 可移植固定寬度型別別名
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned long uint32;
typedef signed char int8;
typedef signed short int16;
typedef signed long int32;
// 推薦 C99 <stdint.h>:uint8_t, int32_t 等標準名稱
3. 記憶體直接存取巨集
#define MEM_B(addr) (*(volatile uint8 *)(addr))
#define MEM_W(addr) (*(volatile uint16 *)(addr))
#define MEM_DW(addr) (*(volatile uint32 *)(addr))
4. 最大/最小值(參數加括號!)
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
5. 結構體成員偏移量與大小
#define OFFSET_OF(type, member) ((size_t)&(((type *)0)->member))
#define SIZE_OF_MEMBER(type, member) sizeof(((type *)0)->member)
6. 位元組序轉換(小端模式)
// 兩字節 → uint16
#define LE_TO_U16(p) (((uint16)(p)[0] << 8) | (p)[1])
// uint16 → 兩字節
#define U16_TO_LE(p, v) do { (p)[0] = (v) >> 8; (p)[1] = (v) & 0xFF; } while(0)
7. 位元運算實用巨集
#define BIT(n) (1UL << (n))
#define SET_BIT(v, n) ((v) |= BIT(n))
#define CLR_BIT(v, n) ((v) &= ~BIT(n))
#define TEST_BIT(v, n) ((v) & BIT(n))
#define GET_BITS(v, lo, hi) (((v) >> (lo)) & ((1UL << ((hi)-(lo)+1)) - 1))
8. 對齊與取模優化
// 向上對齊到 8 的倍數
#define ALIGN8(x) ((((x) + 7) / 8) * 8)
// 2 的冪次取模:x % 2^n == x & (2^n - 1)
#define MOD_POW2(x, n) ((x) & ((1U << (n)) - 1))
9. 字元分類(無標準庫依賴)
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
#define IS_HEX(c) (IS_DIGIT(c) || ((c)>='A'&&(c)<='F') || ((c)>='a'&&(c)<='f'))
#define TO_UPPER(c) (((c)>='a'&&(c)<='z') ? (c)-0x20 : (c))
10. 飽和算術(防溢位)
#define SAT_ADD(a,b) ((a) > UINT_MAX-(b) ? UINT_MAX : (a)+(b))
#define SAT_INC(v) ((v) == UINT_MAX ? UINT_MAX : (v)+1)
11. 陣列元素數量
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
12. I/O 映射存取(嵌入式)
#define INB(port) (*(volatile uint8 *)(port))
#define OUTB(port,v) (*(volatile uint8 *)(port) = (uint8)(v))
// INW/OUTW, IND/OUTD 同理
13. 除錯追蹤巨集
#ifdef DEBUG
#define DBG(fmt, ...) fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#else
#define DBG(fmt, ...) ((void)0)
#endif
14. 多語句巨集:do-while(0) 鐵律
#define LOCK(m) do { pthread_mutex_lock(m); } while(0)
#define UNLOCK(m) do { pthread_mutex_unlock(m); } while(0)
15. 字串化(#)與符號連接(##)進階
// 字串化
#define STR(x) #x
#define XSTR(x) STR(x) // 兩層展開變數值
// 連接
#define DECL_VAR(name) int var_##name
#define MAKE_FN(name) void fn_##name()
// 多層連接
#define NS_JOIN(a,b,c,d) a##_##b##_##c##_##d
16. 可變參數巨集(C99/GNU)
#define LOG(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
// GNU 擴展:## 吃掉前置逗號,支援零參數
17. 常見陷阱與對策
| 陷阱 | 症狀 | 對策 |
| 運算子優先級 | SQR(x+1) → x+1*x+1 | 參數與整體雙重括號 |
| 副作用重複求值 | MAX(i++, j++) → i 增兩次 | 改用 inline 函數 / GNU ({ typeof(x) _x=(x); ... }) |
| 多語句無分組 | if(x) DO(); else ... 語法錯 | do{...}while(0) |
| 巨集遞歸展開 | 編譯器報錯/無限遞歸 | 避免自我引用,用 #undef 間隔 |
18. 最佳實踐總結
- 能用
const/enum/inline/template 就不用巨集。
- 必須用巨集:參數加括號、整體加括號、多行用 do-while(0)。
- 型別別名用
typedef/using,勿用巨集。
- 善用
##、#、__VA_ARGS__ 做元程式設計,但保持可讀性、加註釋。
- 標準庫風格巨集(
offsetof, container_of, ARRAY_SIZE)優先採用經驗驗證版本。