Hi,你好,欢迎来到《快速掌握现代C++编程范式》系列课程。本文是《快速掌握现代C++编程范式》系列课程第7篇,前6篇是:
内联函数
内联函数并不是一个新概念。在C语言中就有内联函数。内联函数是在编译期直接将函数体代码插入到调用方的一种特殊函数。其特点如下:内联函数(inline function)并不是一个新概念。在C语言中就已经有内联函数(C99标准中增加)。普通函数是通过call 函数地址的形式调用。当调用一个普通函数时,函数会被当做一个栈帧(stack frame)入栈,当函数返回时,函数再弹出栈。
内联函数是在编译期直接将函数体代码插入到函数调用方的一种特殊函数。所以在运行时并不存在函数入栈和出栈的操作,性能相对也会更高。其特点如下:
- 通过inline关键字将函数指定为内联函数。
- 内联函数是编译器特性,会在编译阶段替换成函数体。
- 即便用inline关键字把函数声明为内联函数,编译器也不一定将函数变为内联函数。
- inline关键字既可以加在函数声明前面,又可以加在函数实现前面。
- 内联函数也是函数,所以内联函数也可以重载(参考《快速掌握现代C++编程范式》函数重载)。
内联函数示例:
inlineintfoo(inta,intb){returna+b;}
什么时候使用内联函数?
1.函数的代码量比较少,低于10行2.函数的调用频率比较多
举例:
staticinlineintadd_i(inta,intb){return(a+b);}
哪些情况下不会被内联?
虽然我们可以使用inline指示函数内联,但也有不生效的时候。《The design and envolution of C++》2.4节中如下描述: inline 指示字只是一种提示,编译器可以去做,但也常常忽略它们。这在逻辑上是必需的,因为某人可 能写出一个递归的inline函数,编译时无法证明它不会导致无穷递归,试图将这类东西inline就会引起无穷的 编译。让 inline 作为提示在实践中也有优势,因为可以使写编译器的人更容易处理各种病态情况,遇到 它们就简单地不做inline处理。
可以发现,inline关键字只是给编译器一个建议,编译器不一定会接受这种建议。一些编译器,会将简单的函数做内联编译,即使它没有用inline关键字声明。在以下几种情况中,编译器可能不会将函数进行内联编译:
- 函数体过于庞大。
- 对函数进行取地址操作。
- 函数中存在循环、递归语句。
- 函数中存在过多的条件判断语句。
如何强制编译器内联?
以上代码虽然使用了inline关键字,但实际上编译器不一定会进行内联,通过Xcode和CLion查看汇编代码也确实如此。想要强制内联展开,可以使用编译器的attribute属性。如下:
inline__attribute__((always_inline))intadd(intx,inty);
如下是在CLion中,通过打断点查看函数内联情况:
// C++源码include inlineintadd(intx,inty);inlineintadd(intx,inty){returnx+y;}intmain(){std::cout<<"Hello, World!"<<add(2,5)<<std::endl;return0;}// 汇编代码(部分)0x1029b31a2<+34>:movq%rax,-0x10(%rbp)0x1029b31a6<+38>:movl$0x2,%edi0x1029b31ab<+43>:movl$0x5,%esi0x1029b31b0<+48>:callq0x1029b3d9a;symbolstubfor:add(int,int)0x1029b31b5<+53>:movq-0x10(%rbp),%rdi0x1029b31b9<+57>:movl%eax,%esi
通过查看汇编代码,可以发现,虽然我们使用了inline修饰add函数,但实际上函数并没有被内联,而是通过callq指令直接调用。
强制内联:
// C++源码include inline__attribute__((always_inline))intadd(intx,inty);inlineintadd(intx,inty){returnx+y;}intmain(){std::cout<<"Hello, World!"<<add(2,5)<<std::endl;return0;}// 汇编源码(部分)0x10cd141d2<+34>:movq%rax,%rdi0x10cd141d5<+37>:movl$0x2,-0x4(%rbp)0x10cd141dc<+44>:movl$0x5,-0x8(%rbp)0x10cd141e3<+51>:movl-0x4(%rbp),%esi0x10cd141e6<+54>:addl-0x8(%rbp),%esi
通过查看上面汇编代码,可以发现__attribute__((always_inline))确实可以实现强制内联。
PS:如果没有特殊需求,不建议强制内联。
所有文章均为原创,转载请联系作者,并注明出处。
声明:本文部分素材转载自互联网,如有侵权立即删除 。
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别
丞旭猿论坛
暂无评论内容