
1. 引入inline關鍵字的原因
在c/c++中,為了解決一些頻繁呼叫的小函式大量消耗堆疊空間(堆疊記憶體)的問題,特別的引入了inline修飾符,表示為行內函式,
堆疊空間就是指放置程式的區域資料(也就是函式內資料)的記憶體空間,
在系統下,堆疊空間是有限的,假如頻繁大量的使用就會造成因堆疊空間不足而導致程式出錯的問題,如,函式的死回圈遞回呼叫的最終結果就是導致堆疊記憶體空間枯竭,
下面我們來看一個例子:
#include //函式定義為inline即:行內函式inlinechar* dbtest(int a) {return (i %2 >0) ?"奇" :"偶";}int main(){int i =0;for (i=1; i <100; i++) {printf("i:%d 奇偶性:%s /n", i, dbtest(i));
}
}
上面的例子就是標準的行內函式的用法,使用inline修飾帶來的好處我們表面看不出來,其實,在內部的作業就是在每個for回圈的內部任何呼叫dbtest(i)的地方都換成了(i%2>0)?”奇”:”偶”,這樣就避免了頻繁呼叫函式對堆疊記憶體重復開辟所帶來的消耗,
2. inline使用限制
inline的使用是有所限制的,inline只適合涵數體內代碼簡單的涵數使用,不能包含復雜的結構控制陳述句例如while、switch,并且不能行內函式本身不能是直接遞回函式(即,自己內部還呼叫自己的函式),
3. inline僅是一個對編譯器的建議
inline函式僅僅是一個對編譯器的建議,所以最后能否真正行內,看編譯器的意思,它如果認為函式不復雜,能在呼叫點展開,就會真正行內,并不是說宣告了行內就會行內,宣告行內只是一個建議而已,
4. 建議:inline函式的定義放在頭檔案中
其次,因為行內函式要在呼叫點展開,所以編譯器必須隨處可見行內函式的定義,要不然就成了非行內函式的呼叫了,所以,這要求每個呼叫了行內函式的檔案都出現了該行內函式的定義,
因此,將行內函式的定義放在頭檔案里實作是合適的,省卻你為每個檔案實作一次的麻煩,
宣告跟定義要一致:如果在每個檔案里都實作一次該行內函式的話,那么,最好保證每個定義都是一樣的,否則,將會引起未定義的行為,如果不是每個檔案里的定義都一樣,那么,編譯器展開的是哪一個,那要看具體的編譯器而定,所以,最好將行內函式定義放在頭檔案中,
5. 類中的成員函式與inline
定義在類中的成員函式預設都是行內的,如果在類定義時就在類內給出函式定義,那當然最好,如果在類中未給出成員函式定義,而又想行內該函式的話,那在類外要加上inline,否則就認為不是行內的,
例如,
class A{public:voidFoo(int x,int y) { }// 自動地成為行內函式
}
將成員函式的定義體放在類宣告之中雖然能帶來書寫上的方便,但不是一種良好的編程風格,上例應該改成:
// 頭檔案class A{public:voidFoo(int x,int y);
}
// 定義檔案inlinevoid A::Foo(int x,int y){}
6. inline 是一種“用于實作的關鍵字”
關鍵字inline 必須與函式定義體放在一起才能使函式成為行內,僅將inline 放在函式宣告前面不起任何作用,
如下風格的函式Foo 不能成為行內函式:
inlinevoid Foo(int x,int y);// inline 僅與函式宣告放在一起void Foo(int x,int y){}
而如下風格的函式Foo 則成為行內函式:
void Foo(int x,int y);inlinevoid Foo(int x,int y) {}// inline 與函式定義體放在一起
所以說,inline 是一種“用于實作的關鍵字”,而不是一種“用于宣告的關鍵字”,一般地,用戶可以閱讀函式的宣告,但是看不到函式的定義,
盡管在大多數教科書中行內函式的宣告、定義體前面都加了inline 關鍵字,但我認為inline不應該出現在函式的宣告中,這個細節雖然不會影響函式的功能,但是體現了高質量C++/C 程式設計風格的一個基本原則:
宣告與定義不可混為一談,用戶沒有必要、也不應該知道函式是否需要行內,
7. 慎用inline
行內能提高函式的執行效率,為什么不把所有的函式都定義成行內函式?如果所有的函式都是行內函式,還用得著“行內”這個關鍵字嗎?
行內是以代碼膨脹(復制)為代價,僅僅省去了函式呼叫的開銷,從而提高函式的執行效率,
如果執行函式體內代碼的時間,相比于函式呼叫的開銷較大,那么效率的識訓會很少,另一方面,每一處行內函式的呼叫都要復制代碼,將使程式的總代碼量增大,消耗更多的記憶體空間,
以下情況不宜使用行內:
(1)如果函式體內的代碼比較長,使用行內將導致記憶體消耗代價較高,
(2)如果函式體內出現回圈,那么執行函式體內代碼的時間要比函式呼叫的開銷大,類的建構式和解構式容易讓人誤解成使用行內更有效,要當心建構式和解構式可能會隱藏一些行為,如“偷偷地”執行了基類或成員物件的建構式和解構式,
所以不要隨便地將建構式和解構式的定義體放在類宣告中,一個好的編譯器將會根據函式的定義體,自動地取消不值得的行內(這進一步說明了 inline 不應該出現在函式的宣告中),
如果你也想成為程式員,想要快速掌握編程,趕緊關注小編加入學習企鵝圈子吧!
里面有資深專業軟體開發工程師,在線解答你的所有疑惑~編程語言入門“so easy”
資料包含:編程入門、游戲編程、課程設計等,
免費學習書籍:

免費學習資料:

8.總結
行內函式并不是一個增強性能的靈丹妙藥,只有當函式非常短小的時候它才能得到我們想要的效果;但是,如果函式并不是很短而且在很多地方都被呼叫的話,那么將會使得可執行體的體積增大,
最令人煩惱的還是當編譯器拒絕行內的時候,在老的實作中,結果很不盡人意,雖然在新的實作中有很大的改善,但是仍然還是不那么完善的,
一些編譯器能夠足夠的聰明來指出哪些函式可以行內哪些不能,但是大多數編譯器就不那么聰明了,因此這就需要我們的經驗來判斷,如果行內函式不能增強性能,就避免使用它!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/253795.html
標籤:C
