带参数的宏
带参数的宏(函数式宏)像函数一样使用,但本质是文本替换。函数式宏没有函数调用的开销,但也没有类型检查和作用域保护。正确使用需要理解宏展开规则和常见陷阱。
基本语法
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define SQUARE(x) ((x) * (x))
#define ABS(x) ((x) < 0 ? -(x) : (x))
int m = MAX(3, 5); /* ((3) > (5) ? (3) : (5)) → 5 */
int s = SQUARE(4); /* ((4) * (4)) → 16 */
与函数对比
| 特性 | 宏 | 函数 |
|---|---|---|
| 类型检查 | 无 | 有 |
| 副作用 | 可能多次求值 | 一次求值 |
| 代码大小 | 展开后增大 | 固定 |
| 速度 | 无调用开销 | 有调用开销 |
| 调试 | 难(无符号信息) | 容易 |
| 递归 | 不支持 | 支持 |
多语句宏
#define SAFE_FREE(p) do { \
free(p); \
(p) = NULL; \
} while(0)
/* 使用 */
if (condition)
SAFE_FREE(ptr); /* 正确 */
else
/* ... */
不用 do { ... } while(0) 时:
#define BAD_FREE(p) free(p); (p) = NULL
if (condition)
BAD_FREE(ptr); /* 只执行 free */
else /* (p) = NULL 在 if 外执行 */
/* ... */
可变参数宏(C99)
#define LOG(fmt, ...) printf("[LOG] " fmt "\n", __VA_ARGS__)
LOG("Value: %d", 42); /* [LOG] Value: 42 */
常见错误
参数求值多次:
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int x = 5;
int m = MAX(x++, 3); /* x++ 可能执行两次 */
/* 展开:((x++) > (3) ? (x++) : (3)) */
缺少括号:
#define ADD(a, b) a + b
int result = ADD(1, 2) * 3; /* 1 + 2 * 3 = 7,不是 9 */
/* 正确 */
#define ADD(a, b) ((a) + (b))
最佳实践
- 参数和整体都用括号包围
- 避免在宏参数中使用自增/自减
- 复杂逻辑用
inline函数替代 - 多语句宏用
do { ... } while(0) - 可变参数宏注意格式字符串安全