内联函数 = 建议编译器把函数体直接铺到调用点,省掉"跳进去、跳回来"的开销。写法就是在定义前加关键字 inline。代价是代码变胖(每处调用都复制一份),所以它只适合短小、且调用频繁的函数。
6.3 讲调用时提过一句"调用是有代价的"(记返回地址、复制实参、建栈帧),这一节就是针对那份代价的优化。1.1.3 说 C++ 的优点是"高效",内联就是其中一个小零件——它是第一次把"效率"摆上台面的知识点。
一、写法与效果
inline int add(int a, int b) { // 加一个 inline
return a + b;
}
概念上,编译器的处理是:
// 你写的
int s = add(3, 5);
// 编译器大致变成
int s = 3 + 5; // 函数体被"摊"到了这里
"内联"这个名字的意思就是"就地铺开"——像把信封里的内容直接抄到信纸上,而不是每次去抽屉里翻。
二、为什么要内联(省的是什么)
回看 6.3 的调用五步:记位置 → 复制实参 → 跳进去 → 交结果 → 跳回来。如果函数体只有一行 return a + b;,那么这些"跳来跳去的杂事"可能比计算本身还费时间。内联把这一层全免掉:
| 普通函数调用 | 内联函数 | |
|---|---|---|
| 跳转 | 有 | 无(代码直接铺开) |
| 栈帧 | 要建要拆 | 不要 |
| 代码体积 | 一份 | 每处调用各一份(变大) |
| 可调试性 | 好 | 差(调用点看不出是函数) |
一句话取舍:用空间换时间。
三、inline 是"建议",不是"命令"
这一条最关键:inline 只是一个请求,编译器有权拒绝。
编译器通常拒绝内联的情况: - 函数体太大(铺开会让代码膨胀得离谱) - 递归函数(自己都停不下来,怎么铺) - 复杂控制流、取函数地址等操作
反过来:编译器也可能自动内联一些很短的函数(即使你没写 inline)——现代编译器在这件事上比人算得准。
实用结论:写不写 inline 影响不大,真正的决定权在编译器手里。学它是为了知道"有这么个机制、知道它有体积代价"。
四、动手 Demo:体会"内联不改变结果"
#include <iostream>
using namespace std;
inline int add(int a, int b) { // 建议内联
return a + b;
}
inline int max2(int a, int b) { // 另一个适合内联的例子:短小
return (a > b) ? a : b;
}
int main() {
int s = 0;
for (int i = 1; i <= 10; i++) {
s = add(s, i); // 高频调用的小函数
}
cout << "累加结果 = " << s << endl;
cout << "较大值 = " << max2(3, 9) << endl;
return 0;
}
看到什么算成功:
累加结果 = 55
较大值 = 9
功能上和去掉 inline 没有任何区别——这正是要记住的重点:内联不改变结果,只影响效率。它是"引擎盖下的优化",你从输出上看不出来。
30 秒实验:
1. 把两处 inline 都删掉,重新编译运行——输出一模一样(功能不受影响)。
2. 想亲眼看"是否内联",可在 Dev-C++ 的编译器选项里加优化参数(如 -O2)再对比程序大小。普通学习阶段不必深究——记住"短小频繁用内联"这条经验规则就够了。
五、什么该内联、什么不该
| 适合内联 | 不适合内联 |
|---|---|
一行返回值的简单函数(add、max2) |
函数体很长(几十行) |
| 取/设值的短函数(学"类"时会大量遇到) | 递归函数 |
| 被高频调用的热点函数 | 只调用一两次的函数(铺开纯属浪费) |
一句话:内联是给"小而热"的函数准备的。
六、常见误区
- "写了 inline 就一定会内联"——不一定,只是建议,编译器可能拒绝。
- "不写 inline 就一定不内联"——也可能被编译器自动内联。
- "内联能加快所有函数"——长函数内联只会让体积暴涨、缓存命中率下降,可能更慢。
- "内联函数不能有返回值"——无关。
inline和有没有返回值是两件独立的事。 - "inline 函数随便放哪都行"——在多文件工程里,
inline函数的定义通常要放在头文件里,否则链接阶段会出错。本章只写单文件,先记个印象,等学到类和多文件时再兑现。
自测三问(点开对答案)
1. 内联函数省了什么?——函数调用的开销(跳转、建栈帧、复制实参等)。 2. 内联的代价是什么?——代码体积变大(每个调用点都铺一份)。 3. 递归函数能内联吗?——通常不能,编译器会拒绝。- ☐ 6.7 变量的存储类别(下一节)
相关笔记
- 函数调用 —— 调用开销的来源
- C++的特点 —— "高效"这条优点的小零件
- 递归调用 —— 递归为何不能被内联
- 🔷 C++基础 · 索引 —— 全课路线图