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

C語言宏定義細節避坑指南:括號、重複定義、#/##、分號陷阱

     編輯:關於C

宏看似簡單,實則暗藏殺機。本文針對六大高頻錯誤模式(括號缺失、重複定義、危險重定義、`#`/`##` 語義、分號濫用、參數展開順序)逐一拆解,並附帶一道經典面試題深度解析預處理機制。

六大避坑法則

1. 括號!括號!!括號!!!

// 錯誤
#define CAL(x,y) x+y
CAL(2,4)*CAL(2,5)  // → 2+4*2+5 = 15 (預期 6*7=42)

// 正確:參數、整體雙層括號
#define CAL(x,y) ((x)+(y))

2. 重複定義以最後為準

#define PI 3.14
#define PI 10.48
// 程序中 PI = 10.48
// 建議:#ifndef PI #define PI 3.14 #endif

3. 危險的關鍵字重定義

#define int char      // 徹底破壞類型系統
#define break continue // 邏輯反轉
// 絕對禁止!

4. `#` 字符串化 vs `##` 拼接

#define SUM(a,b) printf("a add b = %d", a+b)
SUM(1,2)  // 輸出: a add b = 3  (字面量 a,b)

#define SUM2(a,b) printf(#a " add " #b " = %d", a+b)
SUM2(1,2)  // 輸出: 1 add 2 = 3

#define NAME(x,y) x##y
NAME(Steve, Johnson)  // → SteveJohnson

5. 宏定義切勿帶分號

#define SUM(a,b) ((a)+(b));
SUM(a1,b1) + SUM(a2,b2)  // → ((a1)+(b1));+((a2)+(b2))  語法錯誤
// 正確:#define SUM(a,b) ((a)+(b))

6. 經典面試題:參數展開順序與 `#`/`##` 阻斷展開

#define num 10
#define f(x) #x
#define g(x) f(x)

int main() {
    printf("f(num)=%s  g(num)=%s\n", f(num), g(num));
}
// 輸出: f(num)=num  g(num)=10

// 原理:
// f(num) → #num → "num"      (# 阻斷 num 展開)
// g(num) → f(num) → f(10) → #10 → "10"  (g 先展開參數,再進 f 時參數已是 10)

**口訣**:`#`/`##` 遇到參數**不再遞歸展開**;需展開時加中轉層 (`#define STR(s) _STR(s)`)。

預處理器調試技巧

gcc -E macro.c -o macro.i  // 查看展開後代碼
// 或
gcc -E macro.c > a.txt

最佳實踐清單

  1. 參數、表達式**全加括號**。
  2. 多語句用 `do{}while(0)`。
  3. 避免副作用參數 (`MAX(i++,j++)`)。
  4. 命名加項目前綴 (`MYPROJ_MAX`)。
  5. 善用 `#ifndef` 防重複定義。
  6. 條件編譯調試:`#ifdef DEBUG ... #endif`。

宏是雙刃劍,精通預處理機制,才能駕馭它而不被它傷害!

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