C++的inline
Posted createchance
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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函数,这样可以在一定程度上提高代码的运行效率。
以上是关于C++的inline的主要内容,如果未能解决你的问题,请参考以下文章