在 C 語言宏定義中,`##` 稱為標記連接運算符(Token-Pasting Operator)。它的作用是在宏展開時,將兩個獨立的預處理標記(Token)連接成一個新的標記。
#define MACRO(a, b) a ## b
MACRO(var, 1) // 展開為 var1
C99 標準引入 `__VA_ARGS__`,GCC 進一步支援 `##__VA_ARGS__` 解決「參數為空時多出逗號」的問題:
// 錯誤寫法:調用 debug("Test") 時展開為 fprintf(stderr, "Test" , ) —— 多出逗號,編譯失敗
#define debug(format, args...) fprintf(stderr, format, args)
// 正確寫法:## 會在 __VA_ARGS__ 為空時「吃掉」前面的逗號
#define debug(format, ...) fprintf(stderr, format, ##__VA_ARGS__)
void main(void) {
debug("Test\n"); // ✓ 展開為 fprintf(stderr, "Test\n")
debug("Value: %d\n", 42); // ✓ 展開為 fprintf(stderr, "Value: %d\n", 42)
}
#define DECLARE_FUNC(name) void func_##name(void)
DECLARE_FUNC(init); // 展開為 void func_init(void)
DECLARE_FUNC(cleanup); // 展開為 void func_cleanup(void)
#define MAKE_VAR(type, name) type var_##name
MAKE_VAR(int, count); // int var_count;
#define STRINGIFY(x) #x
#define CONCAT_AND_STRINGIFY(a, b) STRINGIFY(a ## b)
CONCAT_AND_STRINGIFY(Hello, World) // "HelloWorld"
| 場景 | C99 `__VA_ARGS__` | GCC `##__VA_ARGS__` | MSVC `__VA_ARGS__` |
|---|---|---|---|
| 參數為空 | 保留逗號,可能報錯 | 自動移除前置逗號 | 不支援 ##,需雙層宏 |
| 有參數 | 正常工作 | 正常工作 | 正常工作 |
#define LOG_LEVEL_INFO 1
#define LOG_LEVEL_DEBUG 2
#define LOG_LEVEL_ERROR 3
#define LOG(level, fmt, ...) \
do { \
if (CURRENT_LOG_LEVEL >= level) { \
fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
} \
} while(0)
// 使用
LOG(LOG_LEVEL_INFO, "Server started on port %d", 8080);
LOG(LOG_LEVEL_DEBUG, "Connection from %s", client_ip);