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 仍是函数;内联是可能的性能优化,不是保证。