宏是 C 語言元編程利器,用得好能大幅提升可讀性、可移植性與安全性。本文匯總 20 類成熟項目常用宏模式,涵蓋類型抽象、位操作、結構體偏移、字符串化、拼接、調試追蹤等實戰場景。
// 1. 防重複包含
#ifndef COMDEF_H
#define COMDEF_H
// ... 头文件内容
#endif
// 2. 固定寬度類型別名 (跨平台移植核心)
typedef unsigned char boolean;
typedef unsigned long uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
typedef signed long int32;
typedef signed short int16;
typedef signed char int8;
// 3. 記憶體映射讀寫 (嵌入式常用)
#define MEM_B(addr) (*(volatile uint8 *)(addr))
#define MEM_W(addr) (*(volatile uint16 *)(addr))
// 4. 最大/最小值 (參數加括號防副作用)
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
// 5. 結構體成員偏移量 (offsetof 手工實現)
#define FPOS(type, field) ((size_t)&(((type *)0)->field))
// 6. 結構體成員大小
#define FSIZ(type, field) sizeof(((type *)0)->field)
// 7. 端序轉換 (LSB 格式)
#define FLIPW(ray) ((((uint16)(ray)[0]) * 256) + (ray)[1])
#define FLOPW(ray, val) do { (ray)[0] = (val)/256; (ray)[1] = (val)&0xFF; } while(0)
// 8. 變量地址強轉
#define B_PTR(var) ((uint8 *)(void *)&(var))
#define W_PTR(var) ((uint16 *)(void *)&(var))
// 9. 字節拆解
#define WORD_LO(x) ((uint8)((uint16)(x) & 0xFF))
#define WORD_HI(x) ((uint8)((uint16)(x) >> 8))
// 10. 向上對齊到 8 的倍數
#define RND8(x) ((((x) + 7) / 8) * 8)
// 11. 字母大寫 / 數字檢查
#define UPCASE(c) (((c) >= 'a' && (c) <= 'z') ? (c) - 0x20 : (c))
#define DECCHK(c) ((c) >= '0' && (c) <= '9')
#define HEXCHK(c) (DECCHK(c) || ((c)>='A'&&(c)<='F') || ((c)>='a'&&(c)<='f'))
// 12. 飽和加法 (防溢出)
#define INC_SAT(val) ((val) = ((val)+1 > (val)) ? (val)+1 : (val))
// 13. 數組元素個數
#define ARR_SIZE(a) (sizeof(a) / sizeof((a)[0]))
// 14. 2 的冪次取模 (位運算優化)
#define MOD_BY_POWER_OF_TWO(val, mod) ((val) & ((mod)-1))
// 15. I/O 空間映射讀寫 (嵌入式)
#define inp(port) (*(volatile uint8 *)(port))
#define outp(port,v) (*(volatile uint8 *)(port) = (uint8)(v))
// 標準預定義宏
__LINE__ // 當前行號
__FILE__ // 當前文件名
__DATE__ // 編譯日期 "Mmm dd yyyy"
__TIME__ // 編譯時間 "hh:mm:ss"
__STDC__ // 標準符合性 (1=標準)
// 條件調試輸出
#ifdef _DEBUG
#define DEBUGMSG(msg, data) printf(msg); printf("%d %d %s", data, __LINE__, __FILE__)
#else
#define DEBUGMSG(msg, data)
#endif
// 錯誤寫法:if(...) DO(a,b); else ... → 語法錯
#define DO(a,b) a+b; a++;
// 正確寫法:do {...} while(0) 模擬單條語句
#define DO(a,b) do { a+b; a++; } while(0)
| 運算符 | 作用 | 例 | 展開結果 |
|---|---|---|---|
| `#` | 參數變字符串 | `STR(vck)` | `"vck"` |
| `##` | 參數拼接 | `CONS(2,3)` → `2e3` | `2000` |
#define A (2)
#define _STR(s) #s
#define STR(s) _STR(s) // 中轉層強制展開參數
STR(INT_MAX) // → "2147483647" 而非 "INT_MAX"
#define _CONS(a,b) int(a##e##b)
#define CONS(a,b) _CONS(a,b)
CONS(A, A) // → int((2)e(2)) → 2000
// 1. 匿名變量名 (行號防衝突)
#define ___ANONYMOUS1(type,var,line) type var##line
#define __ANONYMOUS0(type,line) ___ANONYMOUS1(type, _anonymous, line)
#define ANONYMOUS(type) __ANONYMOUS0(type, __LINE__)
// ANONYMOUS(static int) → static int _anonymous70;
// 2. 結構體自動填充字符串名
#define FILL(a) {a, #a}
enum ID {OPEN, CLOSE};
struct MSG {int id; const char *msg;};
MSG table[] = {FILL(OPEN), FILL(CLOSE)};
// → {{OPEN,"OPEN"}, {CLOSE,"CLOSE"}}
// 3. 編譯期記錄文件名
#define _GET_FILE_NAME(f) #f
#define GET_FILE_NAME(f) _GET_FILE_NAME(f)
static char FILE_NAME[] = GET_FILE_NAME(__FILE__);
// 4. 數值類型對應字符串緩衝區大小
#define _TYPE_BUF_SIZE(type) sizeof #type
#define TYPE_BUF_SIZE(type) _TYPE_BUF_SIZE(type)
char buf[TYPE_BUF_SIZE(INT_MAX)]; // → char buf[11];
精通宏技巧,讓 C 代碼在編譯期完成更多工作,運行期更輕量!