在C语言中,我们使用宏定义函数这种借助编译器的优化技术来减少程序的执行时间,那么在C++中有没有相同的技术或者更好的实现方法呢?答案是有的,那就是内联函数。内联函数作为编译器优化手段的一种技术,在降低运行时间上非常有用。我们将从:

  1. 什么是内联函数
  2. 为什么要使用内联函数
  3. 内联函数优缺点分析
  4. 何时使用内联函数

  这四个方面对内联函数进行介绍。

什么是内联函数

内联函数是C++的增强特性之一,用来降低程序的运行时间。当内联函数收到编译器的指示时,即可发生内联:编译器将使用函数的定义体来替代函数调用语句,这种替代行为发生在编译阶段而非程序运行阶段。

值得注意的是,内联函数仅仅是对编译器的内联建议,编译器是否觉得采取你的建议取决于函数是否符合内联的有利条件。如何函数体非常大,那么编译器将忽略函数的内联声明,而将内联函数作为普通函数处理。

如何使函数内联

定义函数时,在函数的最前面以关键字“inline”声明函数,即可使函数称为内联声明函数。

例如:

Class A
{
Public:
inline int add(int a, int b)
{
return (a + b);
};
}
Class A
{
Public:
int add(int a, int b);
};
inline int A::add(int a, int b)
{
return (a + b);
}

为什么要使用内联函数

有时候我们会写一些功能专一的函数,这些函数的函数体不大,包含了很少的执行语句。例如在计算1~1000以内的素数时,我们经常会使用开方操作使运算范围缩小,这时我们会写一个函数:

int root(int n)
{
  return (int)sqrt((float)n);
}

然后我们的求范围内素数的函数可以这样写。

int prime(int n)
{
int i;
for (i = ; i <= root(n); i++)
{
if (n%i == )
      return ;
return ;
}
}

当然,把root函数放在循环中不是个不明智的选择,但想象一下,在某个程序上下文内必须频繁地调用某个类似root的函数,其调用函数的花销会有多大:当遇到普通函数的调用指令时,程序会保存当前函数的执行现场,将函数中的局部变量以及函数地址压入堆栈,然后再将即将调用的新函数加载到内存中,这要经历复制参数值、跳转到所调用函数的内存位置、执行函数代码、存储函数返回值等过程,当函数执行完后,再获取之前正在调用的函数的地址,回去继续执行那个函数,运行时间开销简直太多了。

      C++内联函数提供了替代函数调用的方案,通过inline声明,编译器首先在函数调用处使用函数体本身语句替换了函数调用语句,然后编译替换后的代码。因此,通过内联函数,编译器不需要跳转到内存其他地址去执行函数调用,也不需要保留函数调用时的现场数据。
 

inline函数的优缺点分析

通过下面这些优缺点总结你大概会更理解为什么要使用inline函数:

优点:

  1. 它通过避免函数调用所带来的开销来提高你程序的运行速度。
  2. 当函数调用发生时,它节省了变量弹栈、压栈的开销。
  3. 它避免了一个函数执行完返回原现场的开销。
  4. 通过将函数声明为内联,你可以把函数定义放在头文件内。

缺点:

  1. 因为代码的扩展,内联函数增大了可执行程序的体积。
  2. C++内联函数的展开是中编译阶段,这就意味着如果你的内联函数发生了改动,那么就需要重新编译代码。
  3. 当你把内联函数放在头文件中时,它将会使你的头文件信息变多,不过头文件的使用者不用在意这些。
  4. 有时候内联函数并不受到青睐,比如在嵌入式系统中,嵌入式系统的存储约束可能不允许体积很大的可执行程序。

什么时候该使用内联函数

当程序设计需要时,每个函数都可以声明为inline。下面列举一些有用的建议:

  1. 当对程序执行性能有要求时,那么就使用内联函数吧。
  2. 当你想宏定义一个函数时,那就果断使用内联函数吧。
  3. 在类内部定义的函数会默认声明为inline函数,这有利于 类实现细节的隐藏。

关键点

  1. 内联声明只是一种对编译器的建议,编译器是否采用内联措施由编译器自己来决定。甚至在汇编阶段或链接阶段,一些没有inline声明的函数编译器也会将它内联展开。
  2. 编译器的内联看起来就像是代码的复制与粘贴,这与预处理宏是很不同的:宏是强制的内联展开,可能将会污染所有的命名空间与代码,将为程序的调试带来困难。
  3. 所有中类中定义的函数都默认声明为inline函数,所有我们不用显示地去声明inline。
  4. 虚函数不允许内联。
  5. 虽然说模板函数放中头文件中,但它们不一定是内联的。(不是说定义在头文件中的函数都是内联函数)。

C++内联函数的更多相关文章

  1. CG_INLINE,inline 内联函数

    内联函数,即在编译的时候将函数体替换函数调用,从而不需要将parameter,return address进行push/pop stack的操作,从而加速app的运行,然而,会增加二进制文件的大小. ...

  2. 不可或缺 Windows Native (16) - C++: 函数重载, 缺省参数, 内联函数, 函数模板

    [源码下载] 不可或缺 Windows Native (16) - C++: 函数重载, 缺省参数, 内联函数, 函数模板 作者:webabcd 介绍不可或缺 Windows Native 之 C++ ...

  3. C++ 内联函数笔记

    要使用内联函数,必须采取下述措施之一: +在函数声明前加上关键字inline: +在函数定义前加上关键字inline. 通常的做法是省略原型,将整个定义(即函数头和所有函数代码)放在本应提供原型的地方 ...

  4. 我的c++学习(6)默认参数和内联函数

    默认参数 一般情况下,函数调用时实参个数应与形参相同,但为了更方便地使用函数,C++也允许定义具有默认参数的函数,这种函数调用时实参个数可以与形参不相同.“默认参数”指在定义或声明函数时为形参指定默认 ...

  5. iOS OC内联函数 inline的详解

    inline 在iOS中的一些框架中,static inline是经常出现的关键字组合. static自不用多说,表示在当前文件中应用,如 static A, 在其它文件中也可以出现static A. ...

  6. 为什么内联函数,构造函数,静态成员函数不能为virtual函数

    http://blog.csdn.net/freeboy1015/article/details/7635012 为什么内联函数,构造函数,静态成员函数不能为virtual函数? 1> 内联函数 ...

  7. sql:除非另外还指定了 TOP 或 FOR XML,否则,ORDER BY 子句在视图、内联函数、派生表、子查询

    执行sql语句: select * from ( select * from tab where ID>20 order by userID desc ) as a order by date ...

  8. 内联函数inline

    1:使用inline函数的时候,必须使函数体和inline说明结合一起,否则编译器将视他为普通函数处理: false: inline void Coord::setcoord(int a,int b) ...

  9. C/C++ 内联函数

    内联函数具备一般函数的性质,但是不需要调用,而是在编译阶段,会用函数体替换函数名被调用的地方.可以节省调用时间(进出栈.保存上下文). 在编译层面和宏的作用相同.内联函数的展开在编译阶段,宏展开在预处 ...

随机推荐

  1. C++内存对齐总结

    大家都知道,C++空类的内存大小为1字节,为了保证其对象拥有彼此独立的内存地址.非空类的大小与类中非静态成员变量和虚函数表的多少有关. 而值得注意的是,类中非静态成员变量的大小与编译器内存对齐的设置有 ...

  2. .net 分布式架构之任务调度平台

    开源地址:http://git.oschina.net/chejiangyi/Dyd.BaseService.TaskManager .net 任务调度平台 用于.net dll,exe的任务的挂载, ...

  3. javascript单元测试框架mochajs详解

    关于单元测试的想法 对于一些比较重要的项目,每次更新代码之后总是要自己测好久,担心一旦上线出了问题影响的服务太多,此时就希望能有一个比较规范的测试流程.在github上看到牛逼的javascript开 ...

  4. Android 5.0 到 Android 6.0 + 的深坑之一 之 .so 动态库的适配

    (原创:http://www.cnblogs.com/linguanh) 目录: 前序 一,问题描述 二,为何会如此"无情"? 三,目前存在该问题的知名SDK 四,解决方案,1 对 ...

  5. AFNetworking 3.0 源码解读 总结(干货)(上)

    养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ...

  6. 漫谈TCP

    不得不承认,tcp是一个非常复杂的协议.它包含了RFC793及之后的一些协议.能把tcp的所有方面面面具到地说清楚,本身就是个很复杂的事情.如果再讲得枯燥,那么就会更让人昏昏欲睡了.本文希望能尽量用稍 ...

  7. 后缀数组的倍增算法(Prefix Doubling)

    后缀数组的倍增算法(Prefix Doubling) 文本内容除特殊注明外,均在知识共享署名-非商业性使用-相同方式共享 3.0协议下提供,附加条款亦可能应用. 最近在自学习BWT算法(Burrows ...

  8. Python学习

    Python基础教程        网易云课堂-零基础入门学习Python

  9. Oracle:一个用户操作多个表空间中表的问题(转)

    原文地址:http://blog.csdn.net/shmiloy001/article/details/6287317 首先,授权给指定用户. 一个用户的默认表空间只能有一个,但是你可以试下用下面的 ...

  10. Xamarin体验:使用C#开发iOS/Android应用

    Xamarin是Mono创始人Miguel de Icaza创建的公司,旨在让开发者可以用C#编写iOS, Android, Mac应用程序,也就是跨平台移动开发.   简介 Xamarin是基于Mo ...