从网上的一些话来看,我知道GCC足够聪明,可以决定是否内联函数.该inline关键词是只是一个提示:
GCC可以内嵌一个共同的功能,并且可以不内联的内联函数.
但是对于我的项目中的这个功能:
struct vb_pos{
union{
struct{
int offset;
int l;
};
unsigned long long g_offset;
};
};
static inline void vi_write_vtail_smart(struct vi *vi){
struct vb_pos *vhead, *vtail, *cursor;
vhead = &vi->v_head;
vtail = &vi->v_tail;
cursor = &vi->cursor;
int curoff = vi->curr - vi->lines[vi->currl].buf;
cursor->offset = curoff;
if(cursor->g_offset >= vhead->g_offset){
*vtail = *cursor;
}
else{
*vtail = *vhead;
*vhead = *cursor;
}
}
Run Code Online (Sandbox Code Playgroud)
用-O2编译.
我检查了汇编代码,并且知道这个函数是按预期内联的.
但是,当我删除它的inline修饰符并重新编译时,我发现它并不是独行侠.它的函数体出现在最终的二进制文件中:
0000000000000000 <vi_write_vtail_smart>:
0: 48 63 47 14 movslq 0x14(%rdi),%rax
4: 48 8b 17 mov (%rdi),%rdx
7: 48 8d 04 40 lea (%rax,%rax,2),%rax
b: 48 8d 04 c2 lea (%rdx,%rax,8),%rax
f: 48 8b 57 18 mov 0x18(%rdi),%rdx
13: 48 2b 10 sub (%rax),%rdx
16: 89 57 10 mov %edx,0x10(%rdi)
19: 48 8b 47 10 mov 0x10(%rdi),%rax
1d: 48 3b 47 38 cmp 0x38(%rdi),%rax
21: 73 0d jae 30 <vi_write_vtail_smart+0x30>
23: 48 8b 57 38 mov 0x38(%rdi),%rdx
27: 48 89 47 38 mov %rax,0x38(%rdi)
2b: 48 89 57 40 mov %rdx,0x40(%rdi)
2f: c3 retq
30: 48 89 47 40 mov %rax,0x40(%rdi)
34: c3 retq
Run Code Online (Sandbox Code Playgroud)
我想知道,既然海湾合作委员会足够聪明,为什么它没有自己的决定呢?为什么它在我指定时执行内联,而不是在我没有时执行?
因为他没有找到足够的线索做出有力的决定?或者,因为他已经做出了决定,他的决定是:内联与否没有太大的区别,因为你问我,我为你排忧; 否则,我把它作为一个共同的功能.
我想知道真正的原因.
如果这是第一种情况,我认为我们可能需要重新考虑这个帖子开头的观点(在网上非常受欢迎)----至少,GCC并不像他们所说的那么聪明,内联关键词也没有那么无用正如他们所说.
在文章的最后,我想为上面的代码片段的上下文添加更多描述:
1,我本来想vi_write_vtail_smart()给内联到函数A()和B(),其导出为库API,都将被用户经常调用.
2,A()与... B()在同一个文件中vi_write_vtail_smart().
3,vi_write_vtail_smart()仅用于A()和B(),没有其他地方.
4,功能体大小A()约为450字节,B()类似.
5,A() 和B()基本上是纯的机器代码,没什么大环或参与重计算,且只有一个子功能被调用时,除vi_write_vtail_smart().该子功能在另一个文件中.
6,我做了一个小测试,我return;之前添加了一行if(cursor-> g_offset> = vhead-> g_offset){,(我想看看当这个函数足够小时发生了什么),即:
...
int curoff = vi->curr - vi->lines[vi->currl].buf;
cursor->offset = curoff;
return;
if(cursor->g_offset >= vhead->g_offset){
...
Run Code Online (Sandbox Code Playgroud)
并且编译时没有inline修饰符,并检查汇编代码----这次GCC内联它,它的函数定义从最终的二进制文件中消失了.
7,我的开发环境:
ubuntu-16.04/64bit
gcc版本5.4.0 20160609
架构:intel X86 Ivybridge Mobile
9,编译标志(必须再次写入,有些人在阅读时会错过它)-O2 -std = gnu99
AnT*_*AnT 11
根据GCC文档,GCC有一个名为的优化设置-finline-functions.这实际上是使GCC在所有函数上使用其启发式内联条件的设置,即使它们未被声明inline.此设置在-O3优化级别启用.因此,您希望GCC完全自由地将其启发式应用于所有函数,您必须-O3至少指定(或-finline-functions明确指定).
没有-finline-functionsGCC通常不会尝试内联未声明的函数,但inline有一些明显的例外:许多其他内联选项也可能导致非内联函数内联.但是,这些选项针对非常具体的情况
-finline-functions-called-once最早启用-O1.只调用一次的静态函数被内联,即使它们未被声明inline.
-finline-small-functions已启用-O2.如果它导致代码大小减少,它会触发内联,即使未声明该函数inline.
你的函数显然没有传递这些在-O2级别上活动的特定内联过滤器:它相对较大并且(显然)被调用多次.出于这个原因,GCC不会将其视为内联-O2,除非您使用inline关键字明确请求它.请注意,显式inline关键字基本上类似于-finline-functions仅为该特定功能启用的设置.它将使GCC将其视为内联,但不保证内联.
同样,如果您希望GCC完全接管您需要的决策-finline-functions或-O3.显式inline关键字触发内联的事实-O2意味着GCC应该决定内联它-O3而不管是否inline存在.
| 归档时间: |
|
| 查看次数: |
325 次 |
| 最近记录: |