Android中c++inline函数

来源:互联网 发布:淘宝助理5.8.5.0下载 编辑:程序博客网 时间:2024/04/24 22:43

1.inline函数简介
在函数声明或定义中函数返回类型前加上关键字inline即把min()指定为内联。
inline int min(int first, int secend) {/**/};
inline 函数对编译器而言必须是可见的,以便它能够在调用点内展开该函数。与非inline函数不同的是,inline函数必须在调用该函数的每个文本文件中定义。当然,对于同一程序的不同文件,如果inline函数出现的话,其定义必须相同。对于由两个文件compute.C和draw.C构成的程序来说,程序员不能定义这样的min()函数,它在compute.C中指一件事情,而在draw.C中指另外一件事情。如果两个定义不相同,程序将会有未定义的行为:
为保证不会发生这样的事情,建议把inline函数的定义放到头文件中。在每个调用该inline函数的文件中包含该头文件。这种方法保证对每个inline函数只有一个定义,且程序员无需复制代码,并且不可能在程序的生命期中引起无意的不匹配的事情。

2.编译器对inline函数的处理办法
inline对于编译器而言,在编译阶段完成对inline函数的处理。将调用动作替换为函数的本体。但是它只是一种建议,编译器可以去做,也可以不去做。从逻辑上来说,编译器对inline函数的处理步骤一般如下:
(1)将inline函数体复制到inline函数调用点处;
(2)为所用inline函数中的局部变量分配内存空间;
(3)将inline函数的的输入参数和返回值映射到调用方法的局部变量空间中;
(4)如果inline函数有多个返回点,将其转变为inline函数代码块末尾的分支(使用GOTO)。
比如如下代码:

int test(){   int a = 6;   ...... // 此处省略代码未对a经行修改   int b = inline_func(b);   ...... // 此处省略代码未对b经行修改   int c = b + 1;   ...... } inline int inline_func(int q) {   if (q > 10) return -1;   else if (q > 0) return (1 << q) - 1;   else return 0; } 

inline之后的函数代码类似于如下形式:

int test() {   int a = 6;   ...... // 此处省略代码未对a经行修改   int b;   {     int _temp_q = 6;     int _temp;     if (_temp_q > 10) _temp = -1;     else if (_temp_q > 0) _temp = (1 << q) - 1;     else _temp = 0;     b = _temp;   }   ...... // 此处省略代码未对b经行修改   int c = b + 1;   ...... }

优化后

int test(){   int a = 6;   ...... // 此处省略代码未对a经行修改   int b = 0x3f;   ...... // 此处省略代码未对b经行修改   int c = 0x40;   ...... } 

经过以上处理,可消除所有与调用相关的痕迹以及性能的损失。inline通过消除调用开销来提升性能。

3.inline函数使用的一般方法

函数定义时,在返回类型前加上关键字inline即把函数指定为内联,函数申明时可加也可不加。但是建议函数申明的时候,也加上inline,这样能够达到”代码即注释”的作用。

使用格式如下:

inline int functionName(int first, int secend,...) {/****/};inline如果只修饰函数的申明的部分,如下风格的函数foo不能成为内联函数:inline void foo(int x, int y); //inline 仅与函数声明放在一起voidFoo(intx,inty){}

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函数的优点,那么inline函数的缺点有哪些呢?我们来看看:

1、代码膨胀。如果inline函数体过大且编译器还让它inline成功,那么你最终的程序会代码膨胀,从而造成设备缓冲命中率低,引起较多的页面错误,读写硬盘的次数增多,这样程序的性能就下降了!建议:inline函数体一般不要超过5行,不包括循环,不包括递归调用。

2、inline函数内部不要有static变量。inline函数的定义几乎总是放在头文件(.h)里,这允许多个实现文件(.cpp)得以引用。我们知道编译器是分别编译的,所以这个时候,在多个实现文件里就会有多个inline函数的展开,也就是说有个多个static变量,这恐怕不是我们期望的!

3、inline函数无法随着函数库升级而升级。如果f是函数库中的一个inline函数,使用它的用户会将f函数实体编译到他们的程序中。一旦函数库实现者改变f,所有用到f的程序都必须重新编译。如果f是non-inline的,用户程序只需重新连接即可。如果函数库采用的是动态连接,那这一升级的f函数可以不知不觉的被程序使用。

4、不要获取inline函数的地址。如果要取得一个inline函数的地址,编译器就必须为此函数产生一个函数实体,无论如何,编译器无法交出一个“不存在函数”的指针。注意,有些编译器可能会使用类的constructors和destructors的函数指针,用以构造和析构一个class对象的数组。另外类的constructors和destructors可能简单,但是其父类的类的constructors和destructors可能是复杂的,所以类的constructors和destructors往往不是inline函数的最佳选择!

5、inline虚函数往往是无效的。虚函数往往是运行时确定的,而inline是在编译时进行的,所以inline虚函数往往无效。当然如果直接用类的对象来使用虚函数,那么对有的编译器而言,也可起到优化的作用。

6、inline函数无法调试。原因请参见上面编译器将函数inline的步骤。所以请在项目后期,对程序进行profile后,再决定将那些函数inline化。

1、《C++箴言:理解inline化的介入和排除》
2、《C++ inline 函数》
3、《C++语言的设计和演化》2.4 运行时的效率

原创粉丝点击