| 操作符 | 名稱 | 作用 | 示例(x=1) | 展開結果 |
|---|---|---|---|---|
## | Token Pasting(符號連接) | 將兩個標記合併為一個標記 | #define A(x) T_##x | A(1) → T_1 |
# | Stringification(字符串化) | 將參數轉為字符串字面量 | #define C(x) #x | C(1) → "1" |
#@ | Charizing(字符常量化,GCC擴展) | 將參數轉為字符常量 | #define B(x) #@x | B(1) → '1' |
#define DECLARE_VAR(type, name) type var_##name
#define GETTER(type, name) type get_##name() { return var_##name; }
DECLARE_VAR(int, count); // 展開: int var_count;
GETTER(int, count); // 展開: int get_count() { return var_count; }
#define DEBUG_PRINT(fmt, val) \
printf("File %s Line %d: " #val " = " fmt "\n", __FILE__, __LINE__, val)
int x = 42;
DEBUG_PRINT("%d", x);
// 輸出: File main.c Line 10: x = 42
#define UNUSED_PARAM(p) ((void)(p))
void callback(int fd, int events, void* arg) {
UNUSED_PARAM(fd);
UNUSED_PARAM(events);
// 只使用 arg,不觸發 -Wunused-parameter 警告
}
原理:(void)expr 明確告訴編譯器「我故意忽略此表達式的值」,屬標準 C 語法,跨編譯器兼容。
#define LOG(fmt, ...) printf("[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
LOG("User %s login from %s", "admin", "192.168.1.1");
// 輸出: [main.c:20] User admin login from 192.168.1.1
#@ 為 GCC 擴展,**非標準 C**,MSVC 不支援,跨平台項目慎用。## 兩側需有標記,#define PASTE(a,b) a##b 若調用 PASTE(,var) 會報錯。MACRO(i++))可能多次求值,嚴禁在宏中直接使用有副作用的表達式。#ifndef __HEADER_H__ 模式最通用,#pragma once 雖簡潔但非標準。宏三大操作符 ##、#、#@ 分別解決「標記拼接」「變量名轉字符串」「變量名轉字符常量」三類元編程需求。配合 __VA_ARGS__、__FILE__、__LINE__,能構建極具表達力的調試、日誌、代碼生成工具集。**宏無類型檢查、無作用域、難調試**,核心邏輯論盡量用 inline 函數/模板替代,宏專注於「語法層面的代碼生成」。