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

實用 C 巨集技巧集錦

     編輯:關於C語言

1. 記憶體對齊巨集

#define RTA_ALIGNTO 4
#define RTA_ALIGN(len)  (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1))
  • RTA_ALIGNTO:對齊基數(這裡 4 位元組)。
  • RTA_ALIGN(len):將 len 向上調整為 RTA_ALIGNTO 的倍數。常用於 Netlink 訊息、結構體序列化、DMA 緩衝區對齊。

2. 條件編譯除錯輸出

#ifdef DEBUG
#define DPRINT(fmt, ...)  do { printf(fmt, ##__VA_ARGS__); } while (0)
#else
#define DPRINT(fmt, ...)  /* 釋出版本完全展開為空,零開銷 */
#endif
  • do { ... } while (0):確保巨集在語句位置表現如單一語句,支援後接分號,避免 if (...) DPRINT(...); else ... 語法錯誤。
  • ##__VA_ARGS__:GNU 擴展,當可變參數為空時自動移除前導逗號,支援 DPRINT("hello") 與 DPRINT("%d", x) 兩種寫法。
  • 釋出建構 (NDEBUG 或未定義 DEBUG) 時巨集消失,無函數呼叫開銷。

3. 容器偏移量與指標回推

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, TYPE, MEMBER) \
    ((TYPE *)((char *)(ptr) - offsetof(TYPE, MEMBER)))
  • offsetof:標準庫已提供 (<stddef.h>),此處展示原理。
  • container_of:Linux 核心風格,從成員指標反推包含結構體指標。廣泛用於鏈表節點、裝置驅動私有資料結構。

4. 編譯期斷言

#define STATIC_ASSERT(cond, msg) \
    typedef char static_assert_##msg[(cond) ? 1 : -1]

條件為假時產生負數陣列大小編譯錯誤,訊息包含 msg。C11 後請改用標準 _Static_assert(cond, msg)。

5. 最大/最小值(型別安全版)

#define MAX(a, b) ({ \
    typeof(a) _a = (a); \
    typeof(b) _b = (b); \
    _a > _b ? _a : _b; \
})
  • 使用 GNU typeof 與語句表達式,確保參數僅評估一次,支援整數、浮點、指標等可比較型別。
  • 標準 C 可用內聯函數替代:static inline int max(int a, int b) { return a>b?a:b; }。

6. 字串化與連接

#define STR(x) #x
#define XSTR(x) STR(x)          // 雙層展開宏參數
#define CAT(a, b) a##b
#define XCAT(a, b) CAT(a, b)    // 雙層展開
  • #:參數字串化。
  • ##:記號連接。
  • 雙層巨集 (XSTR, XCAT) 確保參數若為宏會先展開再處理。

7. 陣列元素個數

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

**僅適用於靜態陣列**,指標傳入會失效。C++17 可用 std::size(arr)。

8. 位操作輔助

#define BIT(n) (1U << (n))
#define SET_BIT(reg, n)   ((reg) |= BIT(n))
#define CLEAR_BIT(reg, n) ((reg) &= ~BIT(n))
#define TEST_BIT(reg, n)  (((reg) & BIT(n)) != 0)
#define TOGGLE_BIT(reg, n) ((reg) ^= BIT(n))

9. 結構體成員初始化 (C99 指定初始化器輔助)

#define INIT_STRUCT(type, ...) (type){ __VA_ARGS__ }

配合 .member = value 寫法,順序無關、可選初始化。

10. 避免巨集副作用的原則

  1. 參數加括號:#define SQR(x) ((x)*(x))。
  2. 整體加括號:#define ADD(a,b) ((a)+(b))。
  3. 多語句用 do { ... } while(0) 包裹。
  4. 盡量改用 static inline 函數(型別檢查、除錯可見、無副作用)。

巨集是 C 語言的雙面刃:善用可極大提升表達力與效能,濫用則製造難以除錯的災難。建議將上述常用模式收錄至專案共用 macros.h,團隊統一風格。

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