从网上的一些话我知道GCC足够聪明,可以决定是否内联函数。 inline
关键字只是一个提示:
GCC可能内联常用函数,并且可能不内联内联函数。为什么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;
}
}
编译-02。
我检查了汇编代码,知道这个函数按预期内联了。
但是,当我删除它的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
我想知道,因为GCC是足够聪明,为什么没有它有自己的决定?为什么它在我指定时以内联方式执行,而不是当我不指定时执行?
因为他没有找到足够的线索做出有力的决定?或者,因为他已经做出了决定,他的决定是:内在与内在没有太大的区别,并且自从你问我以后,我就会为你内联;否则,我把它作为一个共同的功能。
我想知道真正的原因。
如果是第一种情况,我认为我们可能需要在这篇文章开头重新考虑观点(网上非常流行)----至少,GCC没有他们所说的那么聪明,并且关键词内联并不像他们所说的那样毫无用处。
在文章结束,我要添加更多的描述为上面的代码段的上下文:
1,I原本想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;
如果(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){
...
并编译没有inline
修改,并检查了汇编代码----这时候GCC内联它和它的函数定义从最终的二进制文件中消失。
7,我的开发环境:
Ubuntu的16.04/64
gcc版本5.4.0 20160609
架构:英特尔X86 IvyBridge的移动
9,编译标志(必须在这里写一遍,有些人读取时忽略) -O2 -std = gnu99
不错的问题,但通过指出确切的GCC版本,目标操作系统和目标架构,您可能会做得更好。 – iehrlich
请注意,“inline”关键字仍具有实际含义,与函数是否内联无关:使用关键字,每个翻译单元可能会出现相同的函数定义,因此可能位于头文件中。如果没有关键字,函数定义可能只会出现在每个程序中,因此不应该在头文件中。 – aschepler
因此,如果没有'inline'关键字,GCC *必须*提供一个定义作为命名符号,以防其他翻译单元使用它。但是这并不妨碍它在另一个调用它的函数中内联它。 – aschepler