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

标签 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);
}

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

但是,如果我在 func 的定义前添加 inline 关键字,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

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

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

我的问题是为什么这个代码片段似乎与现代指南相矛盾,例如 When should I write the keyword 'inline' for a function/method?

最佳答案

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

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

在这种情况下,我有点惊讶地看到编译器没有内联 func 。但是,将 static 添加到 func 也会使其内联。很明显,编译器是基于“其他一些函数也可能正在使用 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);
}

它确实内联了 return "HAHA\n"; 左边的 func 部分。

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

关于C++ `inline` 关键字和编译器优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18932237/

相关文章:

c - 为什么我在这里遇到段错误?

c - LD_PRELOAD 未预加载所有符号

c++ - 如何使用 OpenCV 创建用于跟踪手或手指的 Haar Cascade (xml)?

c++ - 在 C++ 'for' 循环中声明用户定义的类类型

c++ - 什么时候使用协程而不是迭代器?

c++ - 懒惰评估是否有效/可优化?

c++ - 为什么 GCC 交叉编译器不能找到所有的库?

c++ - 函数本地结构/类和 natvis 文件

C++ 简单模板递归

c++ - Eclipse CDT 控制台输出未显示在带有路径的调试中,也未显示在没有路径的运行中