内联函数
概念: 以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。当我们频繁调用短小函数时,就会使用内联函数。C语言是通过宏来解决频繁调用的问题的。
然而宏的机制存在一些问题,不信可以试着写一个add的宏,在C语言学完很久以后,写宏会出现各种各样的问题
标准答案:#define add(x,y) ((x) + (y))
这就是内联函数的意义,解决宏函数机制复杂,容易写错的问题。
具体用法:在函数返回值前面加上关键字inline
inline int add(int x, int y)
{
return x + y;
}
这样就和C语言的宏一样,在使用时直接展开。内联函数还解决了宏不支持调试,不进行参数检查的缺点。
内联函数在debug版本下不会展开,只有在release版本下才会展开,这就是它支持调试的原因。
(由图可以看出内联函数还是通过call地址找到对应函数的)
vs编译器一般是看不到release版本下的汇编代码的,release版本下不支持调试,也就看不到汇编代码,但是也可以通过某些操作看到,图中的操作为在debug版本下只对inline进行优化(这种情况下再f11 add就进不去了):
这是优化后的汇编代码:
下面来说说内联函数的特性
1. inline是一种以空间换时间的做法,省去调用函数额开销(指建立函数栈帧)。所以代码很长(一般是10行,具体取决于编译器)或者有循环/递归的函数不适宜使用作为内联函数。
2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。(比如一个10行的函数,调用1000次,展开就是1000*10行指令,不展开则是1000 + 10,(每行代码够需要消耗空间))
3. inline不建议声明和定义分离,分离会导致链接错误。因为inline,所以符号表中没有f函数的标识符
f.h中
f.cpp中
如果这时在test.cpp文件中调用f函数,会出现链接错误:main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl f(int)" (?f@@YAXH@Z),该符号在函数 _main 中被引用
原因在于:在f.h中只有函数的声明,没有函数的实现,所以在编译时,没有办法展开,只能通过连接来处理。而f.cpp中由于声明了inline的关系,所以f函数的标识符不会出现在符号表中,链接的时候就会找不到,所以会出现链接错误。在f.h中定义f函数,在编译的时候就可以展开了。
即使没有对inline进行优化也生成解决方案时也会链接错误。inline终究是内联函数,不优化也保持了一定的内联函数性质,也就是说,debug版本下内联函数支持调试,但是符号表中没有内联函数的标识符,也就不支持定义和声明分开。



