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

C 語言預處理器 # 與 ## 運算符深度解析

     編輯:關於C

# 運算符:字串化

# 將巨集參數轉換為字串常值。

範例 1:變數名與值同步列印

#include <stdio.h>
#define P(A) printf("%s:%d\n", #A, A)

int main(void)
{
    int a = 1, b = 2;
    P(a);        // 輸出:a:1
    P(b);        // 輸出:b:2
    P(a+b);      // 輸出:a+b:3
    return 0;
}

巨集展開:P(a) → printf("%s:%d\n", "a", a);

範例 2:在格式字串中嵌入參數文字

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

SQR(8);   // 輸出:The square of 8 is 64.

若無 #,"The square of x" 中的 x 會被視為普通字元而非參數。

## 運算符:標記粘合

## 將兩側標記合併為單一標記(必須形成合法 C 標記)。

範例:自動產生變數名

#define XNAME(n) x ## n

XNAME(8)   // 展開為:x8
int XNAME(5) = 10;  // 展開為:int x5 = 10;

進階應用:建構識別符

#define DECLARE_ARRAY(name, size) int name ## _arr[size]
#define INIT_ARRAY(name, value) for(int i=0;i

實戰案例:錯誤碼巨集

#define CASE(x, y) case x: _bsd_setlasterror(anApplInstance, BSD_ ## y); break

// 使用:
switch (err) {
    CASE(EINVAL, EINVAL);
    CASE(ENOMEM, ENOMEM);
}
// 展開為:
// case EINVAL: _bsd_setlasterror(anApplInstance, BSD_EINVAL); break;
// case ENOMEM: _bsd_setlasterror(anApplInstance, BSD_ENOMEM); break;

## 將 BSD_ 與參數 y 粘合為 BSD_EINVAL 等完整常數名。

## 限制與注意事項

  • 結果必須是合法 C 標記(以字母或底線開頭,僅含字母數字底線)。
  • 無法粘合關鍵字、常值或運算符產生非法標記(如 1 ## 2、int ## x)。
  • 巨集參數若為另一巨集,## 會阻止參數展開,需雙層巨集間接粘合:
#define PASTE(a, b) a ## b
#define PASTE_INDIRECT(a, b) PASTE(a, b)
#define VALUE 123
PASTE_INDIRECT(VALUE, 456)  // 正確展開為 123456
// PASTE(VALUE, 456) 會嘗試粘合 "VALUE" 與 "456" → "VALUE456"(非預期)

# 與 ## 結合使用

#define LOG_VAR(var) printf(#var " = %d\n", var)
#define MAKE_FUNC(name) void name ## _func(void) { LOG_VAR(name); }

MAKE_FUNC(foo)  // 生成 void foo_func(void) { printf("foo" " = %d\n", foo); }

總結

運算符功能典型用途
#參數字串化除錯列印、自動生成字串常值
##標記粘合自動生成識別符、建構複合名稱、巨集元程式設計

善用這兩個運算符能大幅減少重複程式碼,實現類似模板的元程式能力,但過度使用會降低可讀性,建議配合完整註解並控制在合理範圍內。

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