C宏中的##(token pasting)
以下內容來自GPT
在 C 和 C++ 中,##
運算子稱為“token pasting”運算子或“貼上”運算子,用於宏定義中。當使用 ##
運算子時,它會將前後的標記(token)直接拼接在一起。在 __VA_ARGS__
前面使用 ##
運算子有一個特定的用途,主要是在處理變參宏時避免多餘的逗號。
作用解釋:
在變參宏中,如果你使用 __VA_ARGS__
並且呼叫宏時沒有傳遞任何可變引數,那麼會出現一個多餘的逗號,導致語法錯誤或不期望的行為。例如:
#define DEBUG_LOG(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
假設你這樣呼叫宏:
DEBUG_LOG("A message");
展開後會變成:
fprintf(stderr, "A message", );
這會在 fprintf
函式呼叫中留下一個多餘的逗號,導致編譯錯誤。
為了防止這種情況,使用 ##__VA_ARGS__
來自動去掉這個多餘的逗號。
示例:
#define DEBUG_LOG(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
當 __VA_ARGS__
是空的時候,##
會將前面的逗號自動移除。例如:
-
有可變引數:
DEBUG_LOG("Value: %d", 42);
展開後:
fprintf(stderr, "Value: %d", 42);
-
沒有可變引數:
DEBUG_LOG("A message");
展開後:
fprintf(stderr, "A message");
在這種情況下,##__VA_ARGS__
確保即使沒有傳遞可變引數,宏的展開依然是合法的,不會留下多餘的逗號。
總結:
##__VA_ARGS__
的主要作用是在變參宏中,當 __VA_ARGS__
為空時,自動去掉前面的逗號,確保宏的展開結果是有效的 C/C++ 程式碼。
注意事項
如果用##來連線字串,那麼要注意:這個連線操作發生在宏展開之前。