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

C/C++ 巨集程式設計大全:從基礎定義到核心庫級技巧與避坑指南

     編輯:關於C語言

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. 最佳實踐總結

  1. 能用 const/enum/inline/template 就不用巨集。
  2. 必須用巨集:參數加括號、整體加括號、多行用 do-while(0)。
  3. 型別別名用 typedef/using,勿用巨集。
  4. 善用 ##、#、__VA_ARGS__ 做元程式設計,但保持可讀性、加註釋。
  5. 標準庫風格巨集(offsetof, container_of, ARRAY_SIZE)優先採用經驗驗證版本。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved