首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C語言宏定義進階技巧大全:從防重複包含到調試追蹤

     編輯:關於C

宏是 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

多語句宏安全模式:do-while(0)

// 錯誤寫法: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];

宏定義黃金法則

  1. **參數、表達式全加括號** — 防優先級錯誤。
  2. **多語句用 `do{}while(0)`** — 安全嵌入 `if/else`。
  3. **慎用副作用參數** — `MAX(i++, j++)` 會雙增。
  4. **善用中轉宏** — 解決 `#`/`##` 參數不展開問題。
  5. **命名加前綴** — 避免污染全局命名空間。

精通宏技巧,讓 C 代碼在編譯期完成更多工作,運行期更輕量!

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved