欢迎来到JV的博客
本篇博客为JV学习过程中的随笔,仅供参考,有错误的地方欢迎指正。
inline内联函数的特征
- 与常规函数调用不同,对于内联函数,编译器使用其函数代码替换函数调用;
补充复习一下常规函数调用过程:
执行到函数调用指令
→程序在函数调用后存储该指令的内存地址
→将函数参数复制到堆栈
→跳到标记函数起点的内存单元,执行函数代码(若有返回值会存入寄存器)
→跳回地址被保存的指令处 - 与宏不同,宏无法进行类型检查,只是单纯的文本替换,而内联函数具有函数特性,如果使用宏执行了类似函数的功能,可以考虑将其转换为内联函数;
- 不能包含循环、递归、switch等复杂操作;
- 在类声明中定义的函数,除了虚函数的其他函数都会自动隐式地当成内联函数;
编译器对inline内联函数的处理步骤
- 将inline函数体复制到inline函数调用点处;
- 为所用inline函数中的局部变量分配内存空间;
- 将inline函数的输入参数和返回值映射到调用方法的局部变量空间中;
- 如果inline函数有多个返回点,将其转变为inline函数代码块末尾的分支(使用GOTO)
inline内联函数优缺点
优点
- 内联函数同宏函数一样在被调用处进行代码展开,省去了参数压栈、栈帧开辟与回收,结果返回等操作,从而提高程序运行速度;
- 内联函数相比于宏来说,在代码展开时,会做安全检查或自动类型转换,而宏函数不会;
- 在类中声明并同时定义的成员函数,会自动转化为内联函数,因此内联函数可以访问类的成员变量,宏定义则不能,具体样例可见下面代码片段;
- 内联函数在运行时可调试,而宏函数不可以
#include <iostream>
class Example {
public:
int x;
// 在类定义内直接定义的成员函数,默认为内联函数
void setX(int val) {
x = val;
}
// 这是一个内联函数,可以访问类的成员变量x
inline void printX() {
std::cout << "The value of x is: " << x << std::endl;
}
};
// 宏定义,尝试访问类的成员变量,这是错误的
#define PRINT_X() std::cout << "The value of x is: " << x << std::endl
int main() {
Example obj;
obj.setX(10);
obj.printX(); // 正确,因为printX是类的成员函数,可以访问成员变量x
// PRINT_X(); // 这将编译失败,因为宏不是类的一部分,不能访问x
return 0;
}
缺点
- 代码膨胀。内联函数是以代码膨胀为代价,消除函数调用带来的开销。另一方面,内联函数的调用需要复制代码,使得程序总代码量增大,消耗更多的内存空间。
- 是否内联,程序员不可控制。内联函数只是对编译器的建议,是否对函数内联取决于编译器。
- inline函数库无法随着函数库升级而升级。inline函数的改变需要重新编译,不像non-inline可以直接链接。