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

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

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

若是想要阻止某函数被内联,能够在函数体前加上 __attribute__((noinline)) 。 函数

   

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

inline int foo(int x) { spa

return x+42; 命令行

} 指针

   

int main(int argc, char* argv[]) c++11

{ 递归

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

 

return 0; string

}

   

使用以下命令行获得汇编代码,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/include test.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函数的参数。

相关文章
相关标签/搜索