C++中哪些函数不能声明为inline?

inline关键字仅仅是对编译器的建议,编译器有权力决定一个函数是否在调用处嵌入。因为内联函数要在调用处展开,编译器必须能在每一个调用处能看到该函数的定义,因此最好将函数实现放在头文件中(而且实现在类定义中的成员函数即便不加inline关键字也会自动成为内联函数)。在实现文件中该函数之前要加上inline关键字的方式是有问题的:如果调用的obj文件在函数定义之前生成,那么该处就无法嵌入内联函数了。如果普通函数需要成为内联函数,在定义时加上inline关键字。

  1. 包含了递归、循环等结构的函数一般不会被内联。
  2. 虚拟函数一般不会内联,但是如果编译器能在编译时确定具体的调用函数,那么仍然会就地展开该函数。
  3. 如果通过函数指针调用内联函数,那么该函数将不会内联而是通过call进行调用。
  4. 构造和析构函数一般会生成大量代码,因此一般也不适合内联。
  5. 如果内联函数调用了其他函数也不会被内联。

如果想要阻止某函数被内联,可以在函数体前加上 attribute((noinline)) 。

有时函数是否原地展开与编译时指定的优先级有关,下面就是一个例子:

inline int foo(int x) {

return x+42;

}

int main(int argc, char argv[])*

{

printf("%d\n", foo(42));

return 0;

}

使用如下命令行得到汇编代码,g++ -S -Wall -DDEBUG -D_GNU_SOURCE -std=c++11 -I/usr/include test.cpp:

.section .text._Z3fooi,"axG",@progbits,_Z3fooi,comdat

.weak _Z3fooi

.type _Z3fooi, @function

_Z3fooi:

//rbp寄存器的值入栈,保存main函数的栈基地址

pushq %rbp

//rsp寄存器的值写入到rbp寄存器,将main函数的栈顶指针赋予foo函数的栈底指针

movq %rsp, %rbp

//此时edi寄存器中的值是42,放入foo栈底向上4byte

movl %edi, -4(%rbp)

//42放入eax寄存器

movl -4(%rbp), %eax

//立即数21eax寄存器中的值(42)相加

addl $21, %eax

//恢复main函数的栈底

popq %rbp

//返回

ret

.size _Z3fooi, .-_Z3fooi

.section .rodata

.LC0:

.string "%d\n"

.text

.globl main

.type main, @function

main:

//rbp寄存器的值入栈,保存_start函数的栈基地址

pushq %rbp

//rsp寄存器的值写入到rbp寄存器,将_start函数的栈顶指针赋予main函数的栈底指针

movq %rsp, %rbp

//rsp寄存器的值减去立即数16,即main函数的栈大小为16

subq $16, %rsp

//edi寄存器中的值放入rbp寄存器中的值减4的位置(栈底向上4byte

movl %edi, -4(%rbp)

//rsi寄存器中的值放入rbp寄存器中的值减16的位置(栈底向上16byte

movq %rsi, -16(%rbp)

//立即数42放入edi寄存器

movl $42, %edi

//调用函数foo

call _Z3fooi

//eax寄存器的值(63)放入esi寄存器

movl %eax, %esi

//LC0段地址放入edi寄存器

movl $.LC0, %edi

movl $0, %eax

call printf

movl $0, %eax

leave

ret

.size main, .-main

使用如下命令行生成汇编代码:g++ -S -O -Wall -DDEBUG -D_GNU_SOURCE -std=c++11 -I/usr/includetest.cpp(增加了一个优化选项)

.section .rodata.str1.1,"aMS",@progbits,1

.LC0:

.string "%d\n"

.globl main

.type main, @function

main:

subq $8, %rsp

movl $63, %esi

movl $.LC0, %edi

call printf

movl $0, %eax

addq $8, %rsp

ret

.size main, .-main

可见foo函数并未被调用,而是直接将立即数63放入esi寄存器作为printf函数的参数。
原文链接: https://www.cnblogs.com/CodeComposer/p/5977011.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/242335

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月13日 下午10:18
下一篇 2023年2月13日 下午10:19

相关推荐