原文在這裡
串連
在宏展開過程中把兩個符號串連在一起的特性往往會很有用。我們管這種特性叫符號粘貼或者符號串連。"##" 就是用於符號串連的預先處理操作符。當一個宏展開後, "##" 兩邊的符號就會被組合成一個,然後該組合後的符號會替換"##"兩邊的符號以及"##"本身。通常情況下"##"兩邊的符號都會是標識符,或者一邊是標識符,一邊是預先處理號。粘貼之後,一個更長的標識符就被產生了。這不是唯一有效情況,把兩個數字粘貼成一個數字也是可以的(比如1.5 或者 e3)。同樣,多字元的操作符比如+=也可以通過粘貼產生。
但是,若兩個符號粘貼後不是一個合法的字元,那麼他們就不能被粘在一起。比如說,你不能把x和+粘在一起。如果你一定要這麼做,前置處理器會發出一個警告然後把兩個符號都發射出來。符號兩邊是否需要有空格在標準裡未定義。你經常可以在一些複雜的宏裡發現一些沒必要的"##"。如果編譯器在這種情況下發出警告,一般來講你可以簡單的把"##"去掉就行。
"##"兩邊的符號都可以來自宏內容,這種情況下你也可以在一開始就把他們寫成一個符號。最常見的使用"##"的場合是其中的一個符號或者兩個符號都是宏參數。如果"##"兩邊的符號中有一個是宏參數,在"##"執行前,它會被實際內容替代。在字元化裡,實際內容不會在宏展開前被替換。如果參數為空白,"##"什麼效果也沒有。
有個事項必須要牢記:把注釋替換成空格這件事,c語言的前置處理器會在在做任何事情前完成。所以,你不能指望串連'/' 和 '*' 來產生一個注釋。你可以在"##"兩邊放無數的空格,包括注釋在內。你也可以在宏參數裡寫注釋。但是,"##"出現在宏內容的兩端是非法的。
考慮一段c代碼用於解釋命令。我們可能需要一個命令名表,或者一個包含一下結構內容的數組:
struct command { char *name; void (*function) (void); }; struct command commands[] = { { "quit", quit_command }, { "help", help_command }, ... };
每一個命令裡,名字都出現了兩次,一次在字串裡,一次在函數名裡。這樣的程式不夠“乾淨”。一個把命令名當參數的宏可以有效解決該類問題。字元常量可以用字元化產生,函數名可以用字元粘貼'_command’來產生。以下是完成後的代碼
#define COMMAND(NAME) { #NAME, NAME ## _command } struct command commands[] = { COMMAND (quit), COMMAND (help), ... };