或许我们在 C 语言中听说过内联函数,但是内联函数是首先在 C++ 中提出来的,可能现代的 C 编译器支持内联函数。
C++ 中的 const 常量可以代替宏常数定义,如:const int A = 3; <==> #define A 3;那么在 C++ 中是否有解决方案代替宏代码片段呢?在 C++ 中推荐使用内联函数替代宏代码片段,使用 inline 关键字声明内联函数。内联函数声明时 inline 关键字必须和函数定义结合在一起,否则编译器会直接忽略内联请求。
C++ 编译器可以将一个函数进行内联编译,被 C++ 编译器内联编译的函数叫做内联函数;C++ 编译器直接将函数插入函数调用的地方,内联函数没有普通函数调用时的额外开销(压栈,跳转,返回等);但 C++ 编译器不一定会满足函数的内联请求!
我们以代码为例来进行分析
#include <stdio.h> #define FUNC(a, b) ((a) < (b) ? (a) : (b)) inline int func(int a, int b) { return a < b ? a : b; } int main(int argc, char *argv[]) { int a = 1; int b = 3; int c = FUNC(++a, b); printf("a = %d\n", a); printf("b = %d\n", b); printf("c = %d\n", c); return 0; }
我们在第 3 行定义了宏函数,返回两个数中的较小值;在第 5 行定义函数返回较小值。我们先用宏函数来返回,在第 14 行比较 ++a 和 b 的值,明显返回的是 2,那么最后的值就为 a = 2, b = 3, c = 2;我们来看看结果
我们看到的是返回的是 3,仔细看下程序,我们调用的是宏函数,也就是说,这个 ++a 被执行了两次,所以返回 3 很正常。我们再来把宏函数调用换成函数调用,看看结果
我们看到这次和我们分析的是一致的啦,那么宏函数和函数还是有区别的,宏函数有弊端。
下来我们来讲讲内联函数,内联函数具有普通函数的特征(参数检查,返回类型等);函数的内联请求可能会被编译器拒绝;函数被内联编译后,函数体直接扩展到调用的地方;宏代码片段由预处理器处理,进行简单的文本替换,没有任何的编译过程,因此可能出现副作用。
现代 C++ 编译器能够进行编译优化,一些函数即使没有 inline 声明,也可能被内联编译;一些现代的 C++ 编译器通过了扩展语法,能够对函数进行强制内联,如:g++:__attribute__((always_inline))属性; MSVC:__forcrinline
下来我们以代码为例进行分析
#include <stdio.h> inline int add_inline(int n); int main(int argc, char *argv[]) { int r = add_inline(10); printf(" r = %d\n", r); return 0; } inline int add_inline(int n) { int ret = 0; for(int i=0; i<n; i++) { ret += i; } return ret; }
我们在 VS2010 中通过断点调试进到反汇编,看看内联函数生效了没。在第 8 行通过调用内联函数 add_inline,我们看到汇编函数如下
我们看到有 call 的调用,证明内联请求失败了。还是调用了函数,并没有在这块直接把函数体铺开。这也证明了我们之前所说的不是每一个内联请求都会得到执行。
在 C++ 中 inline 内联编译有这么几种条件限制:a> 不能存在任何形式的循环语句;b> 不能存在过多的条件判断语句;c> 函数体不能过于庞大;d> 不能对函数进行取址操作;e> 函数内联声明必须在函数调用语句之前;
通过对内联函数的学习,总结如下:1、C++ 中可以通过 inline 声明内联函数;2、编译器直接将内联函数体扩展到函数调用的地方;3、inline 只是一种请求,编译器不一定允许这种请求;4、内联函数省去了函数调用时压栈、跳转和返回的开销。
欢迎大家一起来学习 C++ 语言,可以加我QQ:243343083。
原文地址:http://blog.51cto.com/12810168/2113184