您的位置:首页 > 编程语言 > C语言/C++

C/C++中inline/static inline/extern inline的区别及使用

2016-04-24 16:39 246 查看
引入内联函数的目的是为了解决程序中函数调用的效率问题,也是用内联函数取代带参宏定义(函数传参比宏更加方便易用)

inline关键字用来定义一个类的内联函数。

在类体中和类体外定义成员函数是有区别的:在类体中定义的成员函数为内联(inline)函数,在类体外定义的不是。如果你既希望将函数定义在类体外部,又希望它是内联函数,那么可以在声明函数时加 inline 关键字.在类体内部定义的函数也可以加 inline 关键字,但这是多余的,因为类体内部定义的函数默认就是内联函数.如果在类体外定义 inline 函数,则必须将类定义和成员函数的定义都放在同一个头文件中(或者写在同一个源文件中),否则编译时无法进行嵌入。

inline定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换,(像宏一样展开),没有了调用的开销,效率也很高。类的内联函数也是一个真正的函数,编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。然后进行一系列的相关检查,就像对待任何一个真正的函数一样。这样就消除了它的隐患和局限性。inline可以作为某个类的成员函数,当然就可以在其中使用所在类的保护成员及私有成员。

inline使用场景:(1)、可以使用inline函数完全取代表达式形式的宏定义;(2)、内联函数一般只会用在函数内容非常简单的时候,这是因为,内联函数的代码会在任何调用它的地方展开,如果函数太复杂,代码膨胀带来的恶果很可能会大于效率的提高带来的益处。

在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来进行替换。显然,这种做法不会产生转去转回的问题,但是由于在编译时将函数体中的代码被替代到程序中,因此会增加目标程序代码量,进而增加空间开销,而在时间开销上不像函数调用时那么大,可见它是以目标代码的增加为代价来换取时间的节省。内联函数可减少cpu的系统开销,并且程序的整体速度将加快,但当内联函数很大时,会有相反的作用,因此一般比较小的函数才使用内联函数.

有两种内联函数的声明方法,一种是在函数前使用inline关键字,另一种是在类的内部定义函数的代码,这样的函数将自动转换为内联函数,而且没必要将inline放在函数前面。

内联是一种对编译器的请求,下面这些情况会阻止编译器服从这项请求:如果函数中包含有循环,switch或goto语句,递归函数,含有static的函数.

由此可以看出,内联函数和成员函数没什么区别,区别就在于怎样加快函数的执行速度而已。内联函数是浪费空间来节省时间的设置,因为函数的调用是很浪费时间的,写成内联函数可以在每次调用时用函数体内容代替函数调用,有点类似一个宏定义。当函数体语句较少,且没有复杂的循环语句,且调用次数较多时,就可以用内联函数。

内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。编译时,类似宏替换,使用函数体替换调用处的函数名。一般在代码中用inline修饰,但是否能形成内联函数,需要看编译器对该函数定义的具体处理。

"static inline" means "we have to have this function, if you use it, but don't inline it, then make a static version of it in this compilation unit". "extern inline" means "I actually _have_ an extern for this function, but if you want to inline it, here's the inline-version".

static是以前C的用法.目的是让该关键字标识的函数只在本地文件可见,同一个程序的其它文件是不可见该函数的.换句话说,就算你其它文件里包含了同名同参数表的函数定义的话,也是不会引起函数重复定义的错误的.因为static是仅在当前文件可见。

static inline,静态内联函数,它不使用函数调用,直接将汇编代码插入在调用该函数处。

static inline,可以把它认为是一个static的函数,加上了inline的属性。static inline函数和static函数一样,其定义的范围是local的,即可以在程序内有多个不同的定义(只要不位于同一个文件内即可)。

static inline的内联函数,一般情况下不会产生函数本身的代码,而是全部被嵌入在被调用的地方。如果不加static,则表示该函数有可能会被其他编译单元所调用,所以一定会产生函数本身的代码。所以加了static,一般可令可执行文件变小。Linux内核使用的inline函数大多被定义为static 类型。一个"static inline"函数促使编译程序尝试着将其代码插入到所有调用它的程序中。

extern inline表示该函数是已声明过的了.由于函数本身可以声明多次,所以extern对函数的影响仅仅把函数的隐藏属性显式化了. extern 对于非函数的对象是有用的,因为对象声明时会带来内存的分配,而用 extern就表示该对象已经声明过了,不用再分配内存。

extern inline函数的应用范围比较狭窄,一般不建议使用。

以上内容主要整理自:

1. http://www.cnblogs.com/pengyingh/articles/2405718.html
2. http://stackoverflow.com/questions/216510/extern-inline
3. http://wenku.baidu.com/link?url=QVc0SQBmFKDjcz65nQRe5wqsaY-rBp89VAu9iX6aCm2avMORW-IeGf_zYxFYRf4vNi7P-G3eFc7sx_FzzUh2r2EoXEGajf9MWxVm1_sJsVO
以下为测试代码:

static_inline.h:

#ifndef FBC_MESSY_TEST_STATIC_INLINE_HPP_
#define FBC_MESSY_TEST_STATIC_INLINE_HPP_

class FastMath {
public:
int round(float value) { //类体内部定义的函数默认就是内联函数,也可以加 inline 关键字,但这是多余的
return (int)(value + (value >= 0 ? 0.5f : -0.5f));
}

inline int floor(float value); // 声明为内联函数
};

int FastMath::floor(float value)
{
int i = round(value);
float diff = (float)(value - i);
return i - (diff < 0);
}

static inline int Ceil(float value)
{
int i = (int)(value + (value >= 0 ? 0.5f : -0.5f));
float diff = (float)(i - value);
return i + (diff < 0);
}

void test_static_inline1();
void test_static_inline2();

#endif // FBC_MESSY_TEST_STATIC_INLINE_HPP_
static_inline.cpp:

#include "static_inline.hpp"
#include <iostream>

void test_static_inline1()
{
float a = 4.1, b = 4.9;

FastMath math;
int ret1 = math.round(a);
int ret2 = math.floor(a);
int ret3 = math.round(b);
int ret4 = math.floor(b);

std::cout << ret1 << "   " << ret2 << "    " << ret3 << "    " << ret4 << std::endl;
}

void test_static_inline2()
{
float a = 4.1, b = 4.9;

int ret1 = Ceil(a);
int ret2 = Ceil(b);

std::cout << ret1 << "    " << ret2 << "    " << std::endl;
}

GitHubhttps://github.com/fengbingchun/Messy_Test
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: