從網上的一些話我知道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