一、宏的核心高级特性
1. 变参宏(Variadic Macros)
支持不定数量参数,用于灵活处理格式化字符串、日志输出等场景。
#include <stdio.h>
// 定义支持可变参数的调试宏
#define DEBUG_LOG(format, ...) \
printf("[DEBUG] %s:%d | " format "\n", __FILE__, __LINE__, ##__VA_ARGS__)
int main() {
int error_code = 404;
DEBUG_LOG("Connection failed. Error: %d", error_code);
return 0;
}
输出:
2. 符号拼接(Token Pasting)
使用
##
将两个符号合并为新标识符,用于代码生成。
#define MAKE_FUNCTION(name) void name##_print() { printf("Hello, %s!\n", #name); }
// 生成函数: alice_print(), bob_print()
MAKE_FUNCTION(alice)
MAKE_FUNCTION(bob)
int main() {
alice_print(); // 输出:Hello, alice!
bob_print(); // 输出:Hello, bob!
return 0;
}
输出:
3. 字符串化(Stringification)
使用
#
将宏参数转换为字符串字面量。
#define CHECK(condition) \
if (!(condition)) { \
printf("Assertion failed: %s\n", #condition); \
}
int main() {
int x = 10;
CHECK(x == 5); // 输出:Assertion failed: x == 5
return 0;
}
输出:
4. X-Macro(代码生成技术)
通过单一数据源生成多形态代码(如枚举、字符串表、序列化函数)。
// 定义数据源
#define FRUIT_TABLE \
X(APPLE, "Apple") \
X(ORANGE, "Orange") \
X(BANANA, "Banana")
// 生成枚举
typedef enum {
#define X(name, str) FRUIT_##name,
FRUIT_TABLE
#undef X
} Fruit;
// 生成字符串数组
const char* fruit_strings[] = {
#define X(name, str) str,
FRUIT_TABLE
#undef X
};
int main() {
printf("Fruit: %s\n", fruit_strings[FRUIT_ORANGE]); // 输出:Orange
return 0;
}
5. 泛型宏(C11 _Generic)
根据参数类型选择不同实现,模拟泛型编程。
#include <stdio.h>
// 类型分发宏
#define PRINT(x) _Generic((x), \
int: print_int, \
double: print_double \
)(x)
void print_int(int x) { printf("Integer: %d\n", x); }
void print_double(double x) { printf("Double: %.2f\n", x); }
int main() {
PRINT(42); // 输出:Integer: 42
PRINT(3.14); // 输出:Double: 3.14
return 0;
}
6. 编译时断言
利用宏在编译阶段验证条件。
// C11静态断言
#define STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
STATIC_ASSERT(sizeof(int) == 4, "int must be 4 bytes!");
// 传统实现(无C11支持)
#define COMPILE_TIME_ASSERT(cond) \
typedef char __ct_assert[(cond) ? 1 : -1]
COMPILE_TIME_ASSERT(sizeof(float) == 4);
二、高级宏设计技巧
1. 多语句宏封装
使用
do { ... } while(0)
确保宏展开后语法正确。
#define SWAP(a, b) do { \
typeof(a) __temp = a; \
a = b; \
b = __temp; \
} while(0)
int main() {
int x = 10, y = 20;
SWAP(x, y);
printf("x=%d, y=%d\n", x, y); // 输出:x=20, y=10
return 0;
}
2. 防止多次求值
用
({ ... })
(GCC扩展)或临时变量避免副作用。
// GCC语句表达式(非标准C)
#define MAX(a, b) ({ \
typeof(a) __a = (a); \
typeof(b) __b = (b); \
__a > __b ? __a : __b; \
})
int main() {
int x = 5, y = 10;
printf("Max: %d\n", MAX(x++, y++)); // 安全:x=6, y=11
return 0;
}
三、实际应用场景
1. 泛型容器实现
// 定义泛型动态数组宏
#define DEFINE_DYNAMIC_ARRAY(T) \
typedef struct { \
T* data; \
size_t size; \
size_t capacity; \
} DynamicArray_##T; \
void push_##T(DynamicArray_##T* arr, T value) { \
if (arr->size >= arr->capacity) { \
arr->capacity *= 2; \
arr->data = realloc(arr->data, arr->capacity * sizeof(T)); \
} \
arr->data[arr->size++] = value; \
}
// 生成int和double数组类型
DEFINE_DYNAMIC_ARRAY(int)
DEFINE_DYNAMIC_ARRAY(double)
int main() {
DynamicArray_int int_arr = {0};
int_arr.capacity = 2;
int_arr.data = malloc(int_arr.capacity * sizeof(int));
push_int(&int_arr, 42);
return 0;
}
2. 单元测试框架
#define TEST_CASE(name) void test_##name()
#define RUN_TEST(name) do { \
printf("Running test: %s\n", #name); \
test_##name(); \
} while(0)
TEST_CASE(math_add) {
if (1 + 1 != 2) printf("Test failed!\n");
}
int main() {
RUN_TEST(math_add); // 输出:Running test: math_add
return 0;
}
四、注意事项
调试困难
宏展开后的代码难以在调试器中跟踪。作用域污染
宏定义的临时变量可能与其他变量冲突。类型安全缺失
宏不进行类型检查,需谨慎处理参数。平台兼容性
某些宏技巧(如##__VA_ARGS__
)依赖编译器扩展。
五、总结
高级宏的核心价值:
代码生成:减少重复代码(如X-Macro)。
泛型编程:通过
_Generic
实现类型分发。编译时优化:静态断言、常量计算。
推荐场景:
硬件寄存器操作
协议解析
高性能算法优化
避免滥用:过度复杂的宏会降低可读性,优先考虑函数或模板(C++)。