inline 关键字

← MOC | ← C++ 知识地图


// 头文件中定义 inline 函数(多个翻译单元包含不会报重定义)
inline int square(int x) {
    return x * x;
}
 
// C++17:inline 变量,头文件中定义全局变量不重定义
inline int g_count = 0;
 
// 类内定义的成员函数自动是 inline
class Foo {
public:
    int get() { return val; }   // 隐式 inline
private:
    int val = 0;
};

作用

inline 有两层含义,现代 C++ 更强调第二层:

  1. 建议编译器内联展开:把函数调用替换为函数体,省去调用开销。编译器可以忽略这个建议。
  2. 允许多重定义(ODR 豁免):同一个 inline 函数/变量可以在多个翻译单元中定义,只要定义完全相同,链接器会合并为一份。这是头文件中写函数实现的标准做法。

要点

  • inline 函数的定义必须在每个使用它的翻译单元中可见,所以通常放在头文件
  • 类内直接定义的成员函数隐式 inline,不需要显式写
  • C++17 起支持 inline 变量,解决头文件全局变量重定义问题
  • inline 只是对编译器的建议,是否真正内联展开由编译器决定(复杂函数、递归函数通常不会展开)
  • 过度内联会导致代码膨胀(code bloat),反而降低缓存命中率

和 constexpr、宏对比

方式是否类型安全是否编译期求值能否调试典型场景
#define否(文本替换)旧代码兼容
inline 函数小函数、头文件工具函数
constexpr 函数尽量是编译期常量计算

一句话区分:inline 解决的是链接层面的多重定义问题,内联展开只是附带效果;constexpr 解决的是编译期求值#define 是无类型的文本替换,能不用就不用。


C 语言中的 inline(C99)

C99 引入了 inline,但语义和 C++ 不同——没有 ODR 豁免,头文件里写 inline 函数还需要在某个 .c 文件里补一个外部定义,否则链接器找不到符号。

嵌入式 C 的惯用写法是 static inline,每个翻译单元各自有一份,省去外部定义的麻烦:

// 放在 .h 文件,直接用,无需额外 .c 定义
static inline int square(int x) {
    return x * x;
}

HAL 库、FreeRTOS 里大量使用这个写法。纯 inline(不加 static)在 C 里反而少见。