一、無參數宏定義
#define PI 3.1415926
#define R 3.0
#define L 2*PI*R // 可使用已定義宏
#define S PI*R*R
關鍵規則
- 宏名慣用大寫,區別於變量。
- 不以分號結尾,否則分號會參與替換導致語法錯誤。
- 純文本替換,不做類型檢查、不計算值(
3.1W15 也會原樣替換)。
- 作用域:從定義處到文件末尾,可用
#undef 終止。
- 雙引號內的宏名不被替換(
printf("L=%f", L) 中的 L 不展開)。
二、帶參數宏定義
#define S(a,b) a*b // 宏名與括號間不能有空格
陷阱:參數未加括號導致優先級錯誤
area = S(2+3, 3+4); // 展開為 2+3*3+4 = 15,而非 (5)*(7)=35
修正:參數與表達式均加括號
#define S(a,b) ((a)*(b)) // 安全寫法
三、宏調用 vs 函數調用
| 特性 | 宏展開 | 函數調用 |
| 處理階段 | 預編譯(編譯前) | 運行時 |
| 參數傳遞 | 文本替換,無類型檢查 | 求值後傳值/引用,有類型檢查 |
| 內存開銷 | 不分配形參內存,無返回值 | 分配棧幀,有返回值 |
| 代碼膨脹 | 每次調用複製代碼 | 單一代碼段,反覆調用 |
| 調試 | 不可單步進入 | 可調試 |
四、最佳實踐建議
- 常量優先用
const/constexpr,類型安全。
- 簡單函數優先用
inline 函數,兼具效率與類型檢查。
- 宏僅用於:編譯條件控制(
#ifdef)、日志位置(__FILE__, __LINE__)、不可用函數實現的場景(如可變參數日志宏)。
本文出自「趙玉強的博客」,轉載請保留出處:原文鏈接