C++的inline

inline是C++/C的重要特性,主要用于减少函数调用时入栈和出栈操作带来的消耗,但是却使得我们的程序可能会变得庞大,所以说这是一个权衡的事情,典型的“以空间换取时间”的策略。可是,这个策略在很多情况下是可行的,因为相对于空间而言,时间往往显得更加重要一些。
但是inline函数的使用还有一些问题需要注意的,这里总结如下。

inline函数是声明不是定义

C++中的inline函数是一个声明不是定义,这一点需要额外注意。请看以下代码,首先我们有一个a.h头文件:

/*************************************************************************
    > File Name: a.h
    > Author: Baniel Gao
    > Mail: createchance@163.com 
    > Created Time: Tue 23 Aug 2016 09:58:43 PM CST
 ************************************************************************/

#include <iostream>
using namespace std;

inline void func(int a, int b);

很清晰,这里的func好像是说声明了一个func函数,并且他是inline函数。然后它的定义是在a.cpp文件中:

/*************************************************************************
    > File Name: a.cpp
    > Author: Baniel Gao
    > Mail: createchance@163.com 
    > Created Time: Tue 23 Aug 2016 09:59:13 PM CST
 ************************************************************************/

#include "a.h"

inline void func(int a, int b)
{
    cout << a << " " << b << endl;
}

这里好像是给出了func的定义,然后我们在test.cpp中使用这个func函数:

/*************************************************************************
    > File Name: test.cpp
    > Author: Baniel Gao
    > Mail: createchance@163.com 
    > Created Time: Mon 22 Aug 2016 09:58:20 PM CST
 ************************************************************************/

#include "a.h"

int main()
{
    func(1, 2);

    return 0;
}

一切看起来是那么地正常,但是编译的时候出错误了:
这里写图片描述
这个错误的意思是说:gcc编译的时候出现警告说我们使用了func函数但是并没有定义这个函数,因此我们在ld链接的时候出现找不到func这个函数的错误。这是为什么呢?就是因为inline函数同通常的函数是不一样的,inline函数更像是一个放在别的地方的代码块,在编译的时候gcc编译器会将这个代码拷贝到调用它的地方,这样做的好处就是可以减少运行时的函数调用压栈和出栈的时间消耗,坏处就是增加最终结果文件的体积;这也是它卫为什么叫做inline函数的原因,因为它是一个嵌入的代码块函数。因此,从这个意义上看,inline函数和.h头文件中的声明意义是一样的,只是说有这个代码,然后在用的时候拷贝过去。我们其实可以验证我们上面说的事情,那就是我们在编译的时候给出–save-temps选项,留下编译过程中产生的所有中间文件,我们打开a.s汇编文件看下就知道了:

    .file   "a.cpp"
    .local  _ZStL8__ioinit
    .comm   _ZStL8__ioinit,1,1
    .text
    .type   _Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB1029:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
    cmpl    $1, -4(%rbp)
    jne .L1
    cmpl    $65535, -8(%rbp)
    jne .L1
    movl    $_ZStL8__ioinit, %edi
    call    _ZNSt8ios_base4InitC1Ev
    movl    $__dso_handle, %edx
    movl    $_ZStL8__ioinit, %esi
    movl    $_ZNSt8ios_base4InitD1Ev, %edi
    call    __cxa_atexit
.L1:
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1029:
    .size   _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii
    .type   _GLOBAL__sub_I_a.cpp, @function
_GLOBAL__sub_I_a.cpp:
.LFB1030:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $65535, %esi
    movl    $1, %edi
    call    _Z41__static_initialization_and_destruction_0ii
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1030:
    .size   _GLOBAL__sub_I_a.cpp, .-_GLOBAL__sub_I_a.cpp
    .section    .init_array,"aw"
    .align 8
    .quad   _GLOBAL__sub_I_a.cpp
    .hidden __dso_handle
    .ident  "GCC: (Debian 4.9.2-10) 4.9.2"
    .section    .note.GNU-stack,"",@progbits

可以看到,这里并没有一个叫做func的函数,因此上面编译的时候test.s在编译的时候想要调用func时就出现了找不到func函数的错误了。正确的做法是将所有的inline函数都放在.h头文件中就可以了,因为inline函数本身的意义就是一个声明并不是定义。另外,在C++中,如果你在.h头文件中定义了一个类,并且给出这个类中函数的实现,那么这个函数就是inline的,不管你有没有显式说明。

inline有的时候不是inline

真正的inline最终是有gcc决定的,因为inline不是运行时的事情,而是编译时的事情。gcc会最终决定你的inline是不是会真正当成一个inline来处理,通常来讲gcc会根据你的inline函数长度大小来决定,如果你的inline函数实在过于庞大,那么gcc在编译的时候极有可能会给出警告或者错误,甚至默认忽略你的inline声明。毕竟,inline不是给庞大函数设计的,而是那些频繁调用,小巧玲珑的函数设计的。
有的时候,如果你加上了gcc的-O优化选项后,你的一些短小的非inline函数也会变成inline函数,这样可以在一定程度上提高代码的运行效率。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值