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

C 語言預處理器進階:# 字串化、## 符號連接與 __VA_ARGS__ 可變參數巨集實戰

     編輯:關於C語言

一、 # 字串化運算子

在類函式巨集替換部份,# 將巨集參數轉換為字串常值。過程稱「字串化」。

#define PSQR(x) printf("the square of " #x " is %d.\n", (x)*(x))

PSQR(y);      // 展開:printf("the square of " "y" " is %d.\n", (y)*(y));
// 輸出:the square of y is 16.

PSQR(2+4);    // 展開:printf("the square of " "2+4" " is %d.\n", (2+4)*(2+4));
// 輸出:the square of 2+4 is 36.

參數名 y 變成字串 "y",運算式 2+4 變成字串 "2+4"。相鄰字串常值自動合併。

二、 ## 符號連接運算子

將兩個語言符號 (Token) 合併為單一符號。可用於類函式巨集與類物件巨集。

#define XNAME(n) x##n
XNAME(4)  // 展開:x4

#define PXN(n) printf("x" #n " = %d\n", x##n)
int XNAME(1) = 12; // int x1 = 12;
PXN(1);            // printf("x1 = %d\n", x1);
// 輸出:x1 = 12

應用場景:自動生成變數名、函式名、欄位名,構建輕量級元程式設計。

三、 __VA_ARGS__ 可變參數巨集 (C99)

巨集參數列表最後用 ... 表示可變參數,替換部份用 __VA_ARGS__ 承接。

#define PR(...) printf(__VA_ARGS__)

int main() {
    int wt=1, sp=2;
    PR("hello\n");                       // printf("hello\n");
    PR("weight = %d, shipping = %d", wt, sp); // printf("weight = %d, shipping = %d", wt, sp);
    return 0;
}

進階技巧:解決「多餘逗號」問題 (GCC/Clang 擴展)

// 標準 C99:呼叫時至少需一個固定參數
#define LOG(fmt, ...) printf(fmt, __VA_ARGS__)
// LOG("test"); // 錯誤:__VA_ARGS__ 為空,殘留逗號

// GCC 擴展:##__VA_ARGS__ 自動吞噬前置逗號
#define LOG(fmt, ...) printf(fmt, ##__VA_ARGS__)
LOG("test"); // 正常:展開為 printf("test")

MSVC (Visual Studio) 2015+ 也支援 __VA_ARGS__,但 ##__VA_ARGS__ 行為略有不同,需測試驗證。

四、 實戰綜合範例:除錯巨集

#ifdef DEBUG
#define DBG_PRINT(fmt, ...) \
    do { \
        fprintf(stderr, "[DEBUG][%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
    } while(0)
#else
#define DBG_PRINT(fmt, ...) ((void)0)
#endif

// 使用
DBG_PRINT("User %s logged in, id=%d", username, uid);
  • do { ... } while(0) 確保巨集在語法上像單一語句,可安全用於 if/else 後。
  • __FILE__, __LINE__ 定位來源碼位置。
  • 釋出版本展開為空運算,零開銷。

五、 總結

運算子功能適用範圍關鍵點
#參數字串化類函式巨集參數名 → "參數名"
##符號連接類函式/類物件巨集TokenA ## TokenB → TokenAB
__VA_ARGS__可變參數承接類函式巨集 (C99)配合 ... 使用,注意逗號處理

掌握這三大預處理利器,能編寫出極具表達力、類型安全、零執行期開銷的除錯、日誌、序列化等基礎設施巨集。

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