C++ `inline` 关键字和编译器优化

Sun*_*min 5 c++ gcc

我不断听说该inline关键字不再用作现代编译器的提示,而是用于避免多源项目中的多重定义错误。

但今天我遇到了一个编译器遵守关键字的例子。

没有inline关键字的话,代码如下

#include <iostream>

using namespace std;

void func(const int x){
    if(x > 3)    
        cout << "HAHA\n";
    else
        cout << "KKK\n";
}

int main(){
    func(5);
}
Run Code Online (Sandbox Code Playgroud)

使用命令g++ -O3 -S a.cpp,生成未内联的汇编代码func

但是,如果我在 的定义前面添加 inline 关键字func,则func会内联到 中main

生成的汇编代码部分是

.LC0:
    .string "HAHA\n"
.LC1:
.string "KKK\n"
.text
.p2align 4,,15
.globl  _Z4funci
.type   _Z4funci, @function
_Z4funci:
.LFB975:
    .cfi_startproc
    cmpl    $3, %edi
    jg  .L6
    movl    $4, %edx
    movl    $.LC1, %esi
    movl    $_ZSt4cout, %edi
    jmp _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
    .p2align 4,,10
    .p2align 3

main:
.LFB976:
    .cfi_startproc
    subq    $8, %rsp
    .cfi_def_cfa_offset 16
    movl    $5, %edi
    call    _Z4funci
    xorl    %eax, %eax
    addq    $8, %rsp
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc
Run Code Online (Sandbox Code Playgroud)

我的编译器是 gcc 4.8.1 / x86-64。

我怀疑该函数可以在链接过程中内联,但我不确定会发生这种情况,如果是这样,我怎么知道?

我的问题是为什么这个代码片段似乎与现代指南相矛盾,例如 何时应该为函数/方法编写关键字“内联”?

Mat*_*son 4

inline关键字有多种作用。其中之一是向编译器暗示您希望内联该函数 - 然而,这并不意味着编译器必须内联它[几个编译器中有一个扩展说“无论如何,如果有的话,内联这个”可能”,例如 MS__forceinline和 gcc __attribute__(always_inline)]。

如果函数inline是内联的,关键字还允许您拥有具有相同名称的函数的多个实例,而不会出现“同一函数的多个定义”的错误。[但每次函数必须是相同的源]。

在这种情况下,我有点惊讶地看到编译器 NOT inline func。然而,添加statictofunc也会使其内联。很明显,编译器基于这样一个事实来决定这一点:“其他一些函数也可能正在使用func,所以我们无论如何都需要一个副本,并且内联它并没有太多好处。事实上,如果你将一个函数设为静态,那么它就是仅调用一次,即使函数非常大,gcc/g++ 几乎肯定会内联它。

如果您希望编译器内联某些内容,添加inline. 然而,在许多情况下,编译器都会做出适当的选择。例如,如果我将代码更改为:

const char* func(const int x){
    if(x > 3)    
        return "HAHA\n";
    else
        return "KKK\n";
}

int main(){
    cout << func(5);
}
Run Code Online (Sandbox Code Playgroud)

它确实内联了return "HAHA\n";剩下的部分func

编译器决定内联或不内联的逻辑很复杂,其中一部分是“我们获得了多少,以及它占用了多少代码空间” - 调用的开销operator<<(ostream& ,const char *)对于在这种情况下是内联的。不幸的是,理解编译器为什么做出某个决定并不总是容易的......