内联函数

内联函数的引出

    c++从c中继承的一个重要特征就是效率。假如c++的效率明显低于c的效率,那么就会有很大的一批程序员不去使用c++了。
    在c中我们经常把一些短并且执行频繁的计算写成宏,而不是函数,这样做的理由是为了执行效率,宏可以避免函数调用的开销,这些都有预处理来完成。
    但是在c++出现之后,使用预处理宏会出现两个问题:

第一个在c中也会出现,宏看起来像一个函数调用,但是会有隐藏一些难以发现的错误。和实际的函数调用不一致
第二个问题是c++特有的,预处理器不允许访问类的成员,也就是说预处理器宏不能用作类的成员函数

    为了保持预处理宏的效率又增加安全性,而且还能像一般成员函数那样可以在类里访问自如,c++引入了内联函数(inline function).
    内联函数为了继承宏函数的效率,没有函数调用时开销,然后又可以像普通函数那样,可以进行参数,返回值类型的安全检查,又可以作为成员函数。

预处理宏的缺陷

    预处理器宏存在问题的关键是我们可能认为预处理器的行为和编译器的行为是一样的。当然也是由于宏函数调用和函数调用在外表看起来是一样的,因为也容易被混淆。但是其中也会有一些微妙的问题出现:
问题1

#define ADD(x,y) x+y
inline int Add(int x,int y){
    return x + y;
}
void test(){
    int ret1 = ADD(10, 20) * 10; //希望的结果是300
    int ret2 = Add(10, 20) * 10; //希望结果也是300
    cout << "ret1:" << ret1 << endl; //210 宏改为 (x+y)解决
    cout << "ret2:" << ret2 << endl; //300
}

问题2:

#define COMPARE(x,y) ((x) < (y) ? (x) : (y))
int Compare(int x,int y){
    return x < y ? x : y;
}
void test02(){
    int a = 1;
    int b = 3;
    //cout << "COMPARE(++a, b):" << COMPARE(++a, b) << endl; // 3
    cout << "Compare(int x,int y):" << Compare(++a, b) << endl; //2
}

问题3:
    预定义宏函数没有作用域概念,无法作为一个类的成员函数,也就是说预定义宏没有办法表示类的范围。

内联函数基本概念

    在c++中,预定义宏的概念是用内联函数来实现的,而内联函数本身也是一个真正的函数。内联函数具有普通函数的所有行为。唯一不同之处在于内联函数会在适当的地方像预定义宏一样展开,所以不需要函数调用的开销。因此应该不使用宏,使用内联函数。

在普通函数(非成员函数)函数前面加上inline关键字使之成为内联函数。但是必须注意必须函数体和声明结合在一起,否则编译器将它作为普通函数来对待。
    inline void func(int a);
以上写法没有任何效果,仅仅是声明函数,应该如下方式来做:
   inline int func(int a){return ++;}
注意: 编译器将会检查函数参数列表使用是否正确,并返回值(进行必要的转换)。
这些事预处理器无法完成的。

    内联函数的确占用空间,但是内联函数相对于普通函数的优势只是省去了函数调用时候的压栈,跳转,返回的开销。我们可以理解为内联函数是以空间换时间

类内部的内联函数

    为了定义内联函数,通常必须在函数定义前面放一个inline关键字。但是在类内部定义内联函数时并不是必须的。任何在类内部定义的函数自动成为内联函数。

class Person{
public:
    Person(){ cout << "构造函数!" << endl; }
    void PrintPerson(){ cout << "输出Person!" << endl; }
}

     构造函数Person,成员函数PrintPerson在类的内部定义,自动成为内联函数,当然也并不是所有的函数都是内联函数,因为编译器会根据函数的复杂度来决定是否要把函数当作内联函数。

内联函数和编译器

    内联函数并不是何时何地都有效,为了理解内联函数何时有效,应该要知道编译器碰到内联函数会怎么处理?
    对于任何类型的函数,编译器会将函数类型(包括函数名字,参数类型,返回值类型)放入到符号表中。同样,当编译器看到内联函数,并且对内联函数体进行分析没有发现错误时,也会将内联函数放入符号表。
    当调用一个内联函数的时候,编译器首先确保传入参数类型是正确匹配的,或者如果类型不正完全匹配,但是可以将其转换为正确类型,并且返回值在目标表达式里匹配正确类型,或者可以转换为目标类型,内联函数就会直接替换函数调用,这就消除了函数调用的开销。假如内联函数是成员函数,对象this指针也会被放入合适位置。
    类型检查和类型转换、包括在合适位置放入对象this指针这些都是预处理器不能完成的(不能通过宏来实现)。
    但是c++内联编译会有一些限制,以下情况编译器可能考虑不会将函数进行内联编译:

1.不能存在任何形式的循环语句
2.不能存在过多的条件判断语句
3.函数体不能过于庞大
4.不能对函数进行取址操作

    内联仅仅只是给编译器一个建议,编译器不一定会接受这种建议,如果你没有将函数声明为内联函数,那么编译器也可能将此函数做内联编译。一个好的编译器将会内联小的、简单的函数。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容

  • 内联的疑惑 写这篇文章的初衷源自于对netdata项目把C函数声明为static inline的用法不解。从语言特...
    typesafe阅读 2,097评论 1 1
  • 1 内联函数与宏定义 C++ 语言支持函数内联,其目的是为了提高函数的执行效率(速度)。在C程序中,可以用宏代码提...
    woshishui1243阅读 853评论 0 0
  • 内联函数与宏定义 在C中,常用预处理语句#define来代替一个函数定义。例如:#define MAX(a,b) ...
    HQFlying阅读 1,617评论 0 0
  • 代码(OC): -(NSUInteger)retainCount{ returnNSExtraRefCount(s...
    nalis风阅读 1,240评论 0 1
  • 1、常量与宏 C++中的const常量可以替代宏常数定义: 我们还可以利用宏来定义宏代码片段: 但是宏代码块不是函...
    _Ke_阅读 508评论 0 0