static inline內聯函數



內聯函數有些類似於宏。內聯函數的代碼會被直接嵌入在它被調用的地方,調用幾次就嵌入幾次,沒有使用call指令。這樣省去了函數調用時的一些額外開銷,比如保存和恢複函數返回地址等,可以加快速度。不過調用次數多的話,會使可執行文件變大,這樣會降低速度。相比起宏來說,內核開發者一般更喜歡使用內聯函數。因爲內聯函數沒有長度限制,格式限制。編譯器還可以檢查函數調用方式,以防止其被誤用。static inline的內聯函數,一般情況下不會產生函數本身的代碼,而是全部被嵌入在被調用的地方。如果不加static,則表示該函數有可能會被其他編譯單元所調用,所以一定會產生函數本身的代碼。所以加了static,一般可令可執行文件變小。內核裏一般見不到只用inline的情況,而都是使用static inline。 inline關鍵字inline表明要優化函數的可執行代碼,這可以通過將函數的代碼合併到調用程序的代碼中來實現。Linux內核使用的inline函數大多被定義爲static 類型。一個"static inline"函數促使編譯程序嘗試着將其代碼插入到所有調用它的程序中。這一合併能夠免除函數調用的任何開銷,#define語句也可以排除額外的函數調用。另外,使用inline會增加二進制映像的大小,而這會降低訪問CPU高速緩存的速度,所以不能在所有的函數定義中使用它。

 

問:

首先,關於inline就夠煩人了,有的書上說inline關鍵字要加在定義前,聲明時可以省略,有的說聲明時加上inline函數就變成內聯型,有的說聲明和定義形式要保持一致。在一個類中聲明一個函數,函數的實現在外部,無論是僅僅在內部聲明處加inline,還是在外部實現處加inline,或是兩個地方都加,編譯均能通過,而且也無法通過調試的辦法看出對程序到底有啥影響。搞不清到底要怎麼寫這個inline才比較好,不過可以肯定的是,inline函數的定義部分要放在頭文件裏,聲明和定義分開放會編譯出錯。

而且inline還可以和extern關鍵字、static關鍵字合用,在網上搜了一下,linux之父linus說過 "static inline" means "we have to have this function, if you use it, but don't inline it, then make a static version of it in this compilation unit". "extern inline" means "I actually _have_ an extern for this function, but if you want to inline it, here's the inline-version".
這話說的雲裏霧裏的,誰能解釋一下,說說你對static inline 和 extern inline用法的理解。

答:

extern inline表示該函數是已聲明過的了.由於函數本身可以聲明多次,所以extern對函數的影響僅僅把函數的隱藏屬性顯式化了.
extern 對於非函數的對象是有用的,因爲對象聲明時會帶來內存的分配,而用 extern就表示該對象已經聲明過了,不用再分配內存.
static是以前C的用法.目的是讓該關鍵字標識的函數只在本地文件可見,同一個程序的其它文件是不可見該函數的.換句話說,就算你其它文件裏包含了同名同參數表的函數定義的話,也是不會引起函數重複定義的錯誤的.因爲static是僅在當前文件可見.

關於inline函數,你說的大部分的都 是對的.我來給你總結一下吧.
inline函數僅僅是一個建議,對編譯器的建議,所以最後能否真正內聯,看編譯器的意思,它如果認爲你的函數不復雜,能在調用點展開,就會真正內聯,並不是說聲明瞭內聯就會內聯,你聲明內聯只是一個建議而已.
其次,因爲內聯函數要在調用點展開,所以編譯器必須隨處可見內聯函數的定義,要不然,就成了非內聯函數的調用了.所以,這要求你的每個調用了內聯函數的文件都出現了該內聯函數的定義,因此,將內聯函數放在頭文件裏實現是合適的,省卻你爲每個文件實現一次的麻煩.而你所以聲明跟定義要一致,其實是指,如果你在每個文件裏都實現一次該內聯函數的話,那麼,你最好保證每個定義都是一樣的,否則,將會引起未定義的行爲,即是說,如果不是每個文件裏的定義都一樣,那麼,編譯器展開的是哪一個,那要看具體的編譯器而定.所以,最好將內聯函數定義放在頭文件中.
而類中的成員函數缺省都是內聯的,如果你在類定義時就在類內給出函數,那當然最好.如果你在類中未給出成員函數定義,而你又想內聯該函數的話,那在類外要加上inline,否則就認爲不是內聯的.而且剛說了,內聯函數最好放在頭文件內,所以最好在類定義的頭文件裏把類的內聯函數都實現了.
而你說的將聲明與實現分開,其實是不會編譯出錯的,反正我寫那麼多程序都沒試過.將聲明與定義分開的話,這樣的後果會帶來編譯器並不隨處可見該函數定義,所以,只能在你實現定義的那個文件裏,將該函數看成內聯(如果可以內聯的話),在其它文件,仍看成是普通函數.
看到這裏,我想你應該明白了.那麼聲明時加inline,實現時要不要加inline呢?呵呵,留給 lz 思考吧.
extern inline表示該函數是已聲明過的了.由於函數本身可以聲明多次,所以extern對函數的影響僅僅把函數的隱藏屬性顯式化了.
extern 對於非函數的對象是有用的,因爲對象聲明時會帶來內存的分配,而用 extern就表示該對象已經聲明過了,不用再分配內存.
static是以前C的用法.目的是讓該關鍵字標識的函數只在本地文件可見,同一個程序的其它文件是不可見該函數的.換句話說,就算你其它文件裏包含了同名同參數表的函數定義的話,也是不會引起函數重複定義的錯誤的.因爲static是僅在當前文件可見.

關於inline函數,你說的大部分的都 是對的.我來給你總結一下吧.
inline函數僅僅是一個建議,對編譯器的建議,所以最後能否真正內聯,看編譯器的意思,它如果認爲你的函數不復雜,能在調用點展開,就會真正內聯,並不是說聲明瞭內聯就會內聯,你聲明內聯只是一個建議而已.
其次,因爲內聯函數要在調用點展開,所以編譯器必須隨處可見內聯函數的定義,要不然,就成了非內聯函數的調用了.所以,這要求你的每個調用了內聯函數的文件都出現了該內聯函數的定義,因此,將內聯函數放在頭文件裏實現是合適的,省卻你爲每個文件實現一次的麻煩.而你所以聲明跟定義要一致,其實是指,如果你在每個文件裏都實現一次該內聯函數的話,那麼,你最好保證每個定義都是一樣的,否則,將會引起未定義的行爲,即是說,如果不是每個文件裏的定義都一樣,那麼,編譯器展開的是哪一個,那要看具體的編譯器而定.所以,最好將內聯函數定義放在頭文件中.
而類中的成員函數缺省都是內聯的,如果你在類定義時就在類內給出函數,那當然最好.如果你在類中未給出成員函數定義,而你又想內聯該函數的話,那在類外要加上inline,否則就認爲不是內聯的.而且剛說了,內聯函數最好放在頭文件內,所以最好在類定義的頭文件裏把類的內聯函數都實現了.
而你說的將聲明與實現分開,其實是不會編譯出錯的,反正我寫那麼多程序都沒試過.將聲明與定義分開的話,這樣的後果會帶來編譯器並不隨處可見該函數定義,所以,只能在你實現定義的那個文件裏,將該函數看成內聯(如果可以內聯的話),在其它文件,仍看成是普通函數.
看到這裏,我想你應該明白了.那麼聲明時加inline,實現時要不要加inline呢?呵呵,留給 lz 思考吧.

cp:http://blog.csdn.net/zhangxuye_fujitsu/article/details/17261129

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章