12 宏与 inline 函数
1. 带参数宏:文本替换
#define DOUBLE(x) ((x) + (x))
int n = DOUBLE(3 + 1); // 展开为 ((3+1)+(3+1)),结果为 8
宏参数可能被重复求值:
DOUBLE(get_value()); // get_value() 执行两次
// DOUBLE(i++) 展开后会对 i 进行未排序的多次修改:未定义行为
2. static inline:仍然是函数
static inline int double_value(int x)
{
return x + x;
}
int n = double_value(get_value()); // get_value() 只执行一次
static:这里表示函数具有内部链接,适合在头文件定义短小辅助函数。inline:提供内联提示,不保证编译器真的展开。- 与宏不同,函数有参数类型检查,实参表达式只求值一次。
加不加 inline:二极管思维
对比 static 和 static inline,假设编译器分别选择“不内联”和“内联”:
| 写法 | 好处 | 坏处 |
|---|---|---|
| 真正内联 | 省去调用/返回开销,可能更快 | 函数体复制到多个调用点,可能更占 Flash |
| 保留函数调用 | 多处调用共享函数代码,可能更省 Flash | 每次调用可能有额外开销 |
关键限定:inline 只是提示。 不写 inline 也可能被编译器内联;写了也可能保留函数调用。实际速度和代码体积应看优化结果或测量。
工程选择:短小、高频、性能敏感可考虑 static inline;较长、低频、Flash 紧张通常先用 static。头文件中的小函数常用 static inline,其中避免外部定义冲突主要靠 static。
记忆:内联可能用 Flash 空间换调用速度,但不保证一定发生或一定更快。
3. 多语句宏:do { … } while (0)
#define PRINT_TWO() \
do { \
printf("A\n"); \
printf("B\n"); \
} while (0)
if (ready)
PRINT_TWO();
do { ... } while (0)整体是一条语句,避免宏内多条语句脱离if控制。ready == 0时宏体不执行;进入do后才执行一次。- 它解决多语句宏的语法问题,不能避免参数重复求值。
一句话复习:宏是文本替换;static inline 仍是函数;内联是可能的性能优化,不是保证。