天天看点

C++中的内联函数

C++中的内联函数

1. 定义

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

它们看起来像函数,运作起来像函数,比宏要好得多,使用时还不需要承担函数调用的开销。当内联一个函数时,编译器可以对函数体执行特定环境下的优化工作,这样的优化对”正常“的函数调用是不可能的

下面是一个实例,使用内联函数来返回两个数中的最大值:

#include <iostream>
 
using namespace std;
 
inline int Max(int x, int y)
{
   return (x > y)? x : y;
}
 
// 程序的主函数
int main( )
{
 
   cout << "Max (20,10): " << Max(20,10) << endl;
   cout << "Max (0,200): " << Max(0,200) << endl;
   cout << "Max (100,1010): " << Max(100,1010) << endl;
   return 0;
}
           

上面的代码运行后结果为:

Max (20,10): 20
Max (0,200): 200
Max (100,1010): 1010
           

2. 细节

  • 内联函数的关键字为inline
  • 内联函数是一个对编译器的建议,如果函数过于复杂,编译器会不接受你的建议而将函数处理成普通的函数
  • 对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码,否则将会继续使用旧的函数
  • inline关键字必须和函数体定义放在一起才可以实现内联,仅仅将inline放在函数声明之前不起任何作用。inline是一个用于实现的关键字而不是一个用于声明的关键字

    注意:这个说法是《高质量程序设计指南C++/C语言》中的说法,在《C++Primer》中提到应在函数的声明与定义中都加inline

    《高质量程序设计指南C++/C语言》:

    关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用

    如下风格的函数Foo 不能成为内联函数:

    inline void Foo(int x, int y); // inline 仅与函数声明放在一起

    void Foo(int x, int y){}

    而如下风格的函数Foo 则成为内联函数:

    void Foo(int x, int y);

    inline void Foo(int x, int y) // inline 与函数定义体放在一起{}

    所以说,inline 是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。一般地,用户可以阅读函数的声明,但是看不到函数的定义。尽管在大多数教科书中内联函数的声明、定义体前面都加了inline 关键字,但我认为inline 不应该出现在函数的声明中。这个细节虽然不会影响函数的功能,但是体现了高质量C++/C 程序设计风格的一个基本原则:声明与定义不可混为一谈,用户没有必要、也不应该知道函数是否需要内联。

  • 在类中定义的成员函数将自动转化为内联函数

    注意:必须要在类内完成函数定义才会转化成内联函数,在类内声明而在类外定义则不会转化,当然只有函数非常简单时编译器才会处理成内联函数

  • 虚函数不允许内联
  • 在调试时查看汇编会发现内联函数还是使用了call指令进行了函数调用而没有用在调用处展开的方式处理,这是因为debug版本上inline是不起作用的;inline只有在release版本下才能出现

3. 内联函数的优缺点分析

优点:

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

缺点:

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

4.内联函数和宏的区别

  1. 内联函数在运行时可调试,而宏不可以
  2. 编译器会对内联函数的参数类型做安全检查或自动类型转换(同普通函数),而宏则不会
  3. 内联函数可以访问类的成员变量,宏则不能
  4. 在类中定义的成员函数,自动转化为内联函数
  5. inline在和宏相比没有付出任何额外代价的的情况下更安全,《Effective C++》中”Prefer consts,enums,and inlines to #defines“以及《高质量程序设计指南C++/C语言》中”用函数内联取代宏“都建议用inline函数代替带参宏

继续阅读