static inline;常量/位操作掩码 → 用宏;大函数、递归、被取地址 → 普通函数一句话:"想省调用开销又怕宏的坑 → 内联;纯常量掩码 → 宏;大而复杂 → 普通函数。"
内联函数 = 用 inline 修饰,编译器在调用处直接展开函数体(不跳转、不压栈)省调用开销。它是"宏的进化版":白拿了宏的省开销,还补了类型检查和参数只求值一次。但 inline 只是建议,编译器可拒绝;最大代价是代码膨胀。
static inline int max(int a, int b){...} → 调用处展开,无调用开销#define MAX(a,b) ((a)>(b)?(a):(b)) → MAX(x++, y++) 展开后 x/y 求值两次,副作用重复;内联函数参数只求值一次,正常MAX("abc", 3) 宏能编过;imax("abc", 3) 内联报类型错误| 宏 | 内联函数 | 普通函数 | |
|---|---|---|---|
| 时机 | 预处理文本替换 | 编译期展开(建议) | 编译期调用 |
| 类型检查 | ❌ 无 | ✅ 有 | ✅ 有 |
| 参数求值 | 可能多次 | 一次 | 一次 |
| 调用开销 | 无 | 无(若内联成功) | 有 |
| 适合 | 常量、位操作掩码 | 短小频繁的真函数 | 大函数、递归 |
static inline int f(int x){ return x*x; } 后 int (*p)(int) = f; → 不会内联(取地址后必须保留函数实体,编译器拒绝内联该调用点)#define SQUARE(x) ((x)*(x)) vs square(x) → SQUARE(++n) 对 n 求值两次结果错;square(++n) 一次结果对inline 语义复杂(可能不生成独立符号或跨文件重复定义 → 链接报错);static inline = 每个文件各自一份,绝不产生链接冲突。所以嵌入式/内核默认 static inline#define min(x,y) ({ typeof(x) _x=(x); typeof(y) _y=(y); _x<_y?_x:_y; }) 能解决求值多次,但解决不了类型检查、调试、错误信息问题——Linux 内核仍大量用 static inline,编码风格明确"inline 优先于函数式宏"| 相邻概念 | 和本主题的关系 | 孤立理解会犯的错 |
|---|---|---|
| define vs typedef | 宏 vs 内联:内联补了类型检查、求值一次 | 以为内联=宏换个写法 |
| 函数指针 | 被取地址 → 编译器拒绝内联 | 以为 inline 函数不能取地址(能取,只是不内联) |
| 编译过程 | 内联发生在编译优化阶段 | 以为内联是预处理/链接干的事 |
| 性能优化 | 省调用开销 vs 代码膨胀 | 只看到省开销,忘了 Flash/缓存代价 |
2026-08-03
每主题一页,复习时只翻本目录。