1.inline 函数

1.1定义:inline 函数由 inline 关键字定义,当函数功能简单,使用评率高,为了提高效率,直接将函数的代码嵌入到程序中。但缺点是:(1)相同代码重复书写;(2)程序可读性往往没有使用函数的好。 为了进一步协调效率和可读性之间的矛盾,c++提供了另一种方法,即定义内联函数,方法是在定义函数时加修饰词inline.

intline bool IsNumber(char ch)

{

return ch>='0'&&ch<='9'?1:0;

}

加inline关键字将其改写成内联函数,在编译期间编译器能够在调用点内联展开该函数。

实例:

在debug模式下,设置编译器。

 注意:

        inline是一种以空间换时间的做法,省去调用函数额开销,但当函数体的代码过长或者是递归函数,即使是加上inline关键字,也不会在调用点以内联展开该函数。

         inline对编译器而言,仅仅只是一个建议,编译器会自动优化。

         inline不建议声明和分离,分离会导致链接错误,因为inline被展开,就没有函数的地址了,链接就会找不到。

1.2编译器对 inline 函数的处理办法
    编译器在编译阶段完成对 inline 函数的处理,即对 inline 函数的调用替换为函数的本体。但 inline 关键字对编译器只是一种建议,编译器可以这样去做,也可以不去做。从逻辑上来说,编译器对 inline 函数的处理步骤一般如下:
(1)将 inline 函数体复制到inline函数调用处;
(2)为所用 inline 函数中的局部变量分配内存空间;
(3)将 inline 函数的的输入参数和返回值映射到调用方法的局部变量空间中;
(4)如果 inline 函数有多个返回点,将其转变为 inline 函数代码块末尾的分支(使用GOTO)。inline 通过消除调用开销来提升性能。

3.inline 函数使用的一般方法
   函数定义时,在返回类型前加上关键字 inline 即把函数指定为内联,函数申明时可加也可不加。使用格式为:inline int functionName(int first, int secend,...) {/****/};
4.inline 函数的优点与缺点
inline函数相对宏函数有如下优点:
(1)内联函数同宏函数一样将在被调用处进行代码展开,省去了参数压栈、栈帧开辟与回收,结果返回等,从而提高程序运行速度。

(2)内联函数相比宏函数来说,在代码展开时,会做安全检查或自动类型转换(同普通函数),而宏定义则不会。
例如:

#define MAX(a,b) ((a)>(b)?(a):(b))//宏函数

inline int MAX(int a,int b)//内联函数
{
    return a>b?a:b;
}

   使用宏函数时,其书写语法也较为苛刻,如果对宏函数出现如下错误的调用MAX(a,"Hello"); 宏函数会错误地比较int和字符串,没有参数类型检查,但是使用内联函数的时候,会出现类型不匹配的编译错误。

(3)在类中声明同时定义的成员函数,自动转化为内联函数,因此内联函数可以访问类的成员变量,宏定义则不能。

(4)内联函数在运行时可调试,而宏定义不可以。

inline函数的缺点
(1)代码膨胀。
inline函数带来的运行效率是典型的以空间换时间的做法。

(2)inline 函数无法随着函数库升级而升级。
如果f是函数库中的一个inline函数,使用它的用户会将f函数实体编译到他们的程序中。

(3)是否内联,程序员不可控。
inline函数只是对编译器的建议,是否对函数内联,决定权在于编译器。

5.inline函数的注意事项

(1)使用函数指针调用内联函数将会导致内联失败。
也就是说,如果使用函数指针来调用内联函数,那么就需要获取inline函数的地址。如果要取得一个inline函数的地址,编译器就必须为此函数产生一个函数实体,那么就内联失败。

(2)如果函数体代码过长或者有多重循环语句,if或witch分支语句或递归时,不宜用内联。

(3)类的 constructors、destructors 和虚函数往往不是 inline 函数的最佳选择。
类的构造函数(constructors)可能需要调用父类的构造函数,析构函数同样可能需要调用父类的析构函数,二者背后隐藏着大量的代码,不适合作为inline函数。虚函数(destructors)往往是运行时确定的,而inline是在编译时进行的,所以内联虚函数往往无效。如果直接用类的对象来使用虚函数,那么对有的编译器而言,也可起到优化作用。

(4)至于内联函数是定义在头文件还是源文件的建议。
内联展开是在编译时进行的,只有链接的时候源文件之间才有关系。所以内联要想跨源文件必须把实现写在头文件里。如果一个 inline 函数会在多个源文件中被用到,那么必须把它定义在头文件中。
(5)能否强制编译器进行内联操作?
也有人可能会觉得能否强制编译器进行函数内联,而不是建议编译器进行内联呢?很不幸的是目前还不能强制编译器进行函数内联,如果使用的是 MS VC++, 注意 __forceinline 如同 inine 一样,也是一个用词不当的表现,它只是对编译器的建议比inline更加强烈,并不能强制编译器进行inline操作。

6.小结


inline函数与普通函数的比较

        普通函数有开栈和清栈,inline函数无开栈和清栈。

        当执行开销(代码小)< 调用开销(开栈)时,建议用inline

       当执行开销(代码小)> 调用开销(开栈)时,不建议使用inline

inline和static 的区别

   (1)内联函数没有开栈清栈的开销,static函数有;

  (2)inline编译阶段代码展开导致函数本文件可见,而static是因为符号属性为local本文件可见。

inline和宏的区别

                (1)inline编译时处理有类型检查,安全检查和语法判断等功能,宏预编译时处理无类型检查和安全检查,只是简单的替换

               (2)宏无法调试,而内联可以进行调试。

               (3)内联比宏更加安全,是一种更加安全的宏   

                  (4) 内联函数在编译时展开,带参的宏在预编译时展开

                   内联函数直接嵌入到目标函数代码中,带参的宏是简单的作文本替换

相同点:  两个都代码展开,省去了参数压栈、栈帧开辟与回收,结果返回等,从而提高运行速度。

注:

一般写在头文件中
只在release版本生效
给编译器的一个建议,循环、递归、switch一定不会出现inline。
inline基于实现,不是基于声明,即在声明点无效(先声明后内联)
 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐