現代 C (C11/C17/C23)

字串化(#)與符號黏接(##)

/ STRING-eye-zing /

前置處理器有兩個建構文字的特殊運算子。字串化以單一 # 表示,把巨集引數變成字串常值:你傳入的任何東西都會變成引號之間的字元。符號黏接以 ## 表示,把兩個符號黏成一個新符號。兩者都發生在前置處理階段,在真正的編譯器看到程式碼之前。

字串化:在 #define STR(x) #x 中,呼叫 STR(hello) 得到常值 "hello",STR(1+2) 得到 "1+2"——引數的文字被原樣擷取並加上引號。符號黏接:在 #define CAT(a,b) a##b 中,呼叫 CAT(foo, bar) 產生單一識別字 foobar;這就是你如何用片段拼出變數或函式名稱。一個有用的細節是兩層巨集技巧:若要字串化另一個巨集的「值」而非它的名字,需透過輔助巨集,例如 #define STR(x) #x 與 #define XSTR(x) STR(x),於是 XSTR(VERSION) 會先展開 VERSION 再把結果字串化。

它們對程式碼產生、除錯輔助(印出運算式及其值)、以及從基底名稱拼出識別字很有用。提醒:# 與 ## 作用於「未經展開」的原始引數符號,這正是為何需要那層額外的間接來在黏接或字串化之前先展開巨集;而黏接出無法構成單一合法符號的東西是未定義行為。

#define STR(x) #x #define XSTR(x) STR(x) // 先展開 x,再字串化 #define CAT(a,b) a##b #define VERSION 3 XSTR(VERSION) // -> "3" (STR(VERSION) 會得到 "VERSION") CAT(my_, fn) // -> 識別字 my_fn

# 把引數文字加上引號;## 黏接符號;兩層的 XSTR 技巧迫使內層巨集先展開。

# 與 ## 作用於未經展開的原始引數,所以要字串化或黏接某巨集的「值」需要額外一層間接;黏接成不合法的符號是未定義行為。

又稱
stringificationtoken concatenation字串化與符號連接運算子