我一直听说 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/