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

C 語言巨集(#define)進階用法與常見陷阱全解析

     編輯:關於C語言

1. 簡單常數巨集

#define MAX 1000
for (int i = 0; i < MAX; ++i) { ... }  // 預處理階段直接替換為 1000

2. 類函數巨集與運算子優先級陷阱

#define MAX(x, y) ((x) > (y) ? (x) : (y))  // 正確:參數與整體加括號

// 錯誤範例
#define ADD(a, b) a + b
int c = 10 * ADD(2, 3);  // 展開為 10 * 2 + 3 = 23,非預期的 50

鐵律:巨集定義中,每個參數與整個表達式都要用括號包裹。

3. 巨集 vs typedef:指標宣告的差異

#define PTR int*
PTR a, b;   // 展開為 int* a, b;  → a 是指標,b 是 int(陷阱!)

typedef int* Ptr;
Ptr a, b;   // a、b 皆為 int*(正確)

型別別名請用 typedef,巨集僅做文字替換,不具備型別語意。

4. 字串化(#)與符號連接(##)

#define STR(x) #x
#define CONCAT(a, b) a##b

STR(hello)      → "hello"
CONCAT(var, 1)  → var1

應用場景:自動生成變數名、編譯期字串化除錯資訊。

5. 多行巨集:do-while(0) 慣用語

#define SAFE_FREE(p) do { free(p); (p) = NULL; } while(0)

if (cond) SAFE_FREE(ptr);  // 安全:單一語句,配合分號無誤
else ...

do { ... } while(0) 確保巨集在 if-else、循環體中表現如單一語句,避免「分號吞噬」與「多語句分組」問題。

6. 進階技巧:偏移量、容器_of、編譯期斷言

// 結構體成員偏移量(Linux 核心風格)
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)

// 從成員指標反推結構體指標
#define container_of(ptr, TYPE, MEMBER) \
    ((TYPE *)((char *)(ptr) - offsetof(TYPE, MEMBER)))

// C11 靜態斷言
#define STATIC_ASSERT(cond) _Static_assert(cond, #cond)

7. 除錯巨集:__FILE__、__LINE__、__func__

#ifdef DEBUG
#define LOG(fmt, ...) fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#else
#define LOG(fmt, ...) ((void)0)
#endif

釋出版本自動消除,零開銷。

總結:巨集黃金法則

  1. 盡量用 const/enum/inline/template 替代巨集(型別安全、作用域受控)。
  2. 必須用巨集時:參數加括號、整體加括號、多行用 do-while(0)。
  3. 勿用巨集定義型別別名,改用 typedef/using。
  4. 善用 #、##、__VA_ARGS__ 實現元程式設計,但保持可讀性。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved