C++編程中隊內(nèi)聯(lián)函數(shù)的理解和使用
函數(shù)調(diào)用過程
c++經(jīng)過編譯生成可執(zhí)行程序文件exe,存放在外存儲器中。程序啟動,系統(tǒng)從外存儲器中將可執(zhí)行文件裝載到內(nèi)存中,從入口地址(main函數(shù)起始處)開始執(zhí)行。程序執(zhí)行中遇到了對其他函數(shù)的調(diào)用,就暫停當(dāng)前函數(shù)的執(zhí)行,并保存下一條指令的地址作為從被調(diào)函數(shù)返回后繼續(xù)執(zhí)行的入口點,保存現(xiàn)場。然后轉(zhuǎn)到被調(diào)函數(shù)的入口地址執(zhí)行被調(diào)函數(shù)。遇到return語句或者被調(diào)函數(shù)結(jié)束后,恢復(fù)先前保存的現(xiàn)場,從先前保存的返回地址處繼續(xù)執(zhí)行主調(diào)函數(shù)的其余部分。
內(nèi)聯(lián)函數(shù)
函數(shù)調(diào)用需要進(jìn)行現(xiàn)場保護(hù),以便在函數(shù)調(diào)用之后繼續(xù)進(jìn)行。函數(shù)調(diào)用后還需要恢復(fù)現(xiàn)場才能繼續(xù)執(zhí)行。這都需要系統(tǒng)開銷,影響了程序的效率。
內(nèi)聯(lián)函數(shù)在編譯的時候?qū)⑺{(diào)用的函數(shù)代碼直接嵌入到主調(diào)函數(shù)中,定義方式就是在普通的函數(shù)定義前面加上inline,不存在程序流程跳轉(zhuǎn)和返回,但是增加了程序代碼。內(nèi)聯(lián)函數(shù)函數(shù)體不能含有復(fù)雜的結(jié)構(gòu)控制語句,適用于1-5行的小函數(shù)。當(dāng)函數(shù)規(guī)模比較大的時候,函數(shù)運行的時間相對與函數(shù)的調(diào)用和返回時間大很多,綜合時間和空間考慮,用內(nèi)聯(lián)沒有太大意義。
原理:
對于任何內(nèi)聯(lián)函數(shù),編譯器在符號表里放入函數(shù)的聲明(包括名字、參數(shù)類型、返回值類型)。如果編譯器沒有發(fā)現(xiàn)內(nèi)聯(lián)函數(shù)存在錯誤,那么該函數(shù)的代碼也被放入符號表里。在調(diào)用一個內(nèi)聯(lián)函數(shù)時,編譯器首先檢查調(diào)用是否正確(進(jìn)行類型安全檢查,或者進(jìn)行自動類型轉(zhuǎn)換,當(dāng)然對所有的函數(shù)都一樣)。如果正確,內(nèi)聯(lián)函數(shù)的代碼就會直接替換函數(shù)調(diào)用,于是省去了函數(shù)調(diào)用的開銷。
內(nèi)聯(lián)函數(shù)與宏的區(qū)別
1.內(nèi)聯(lián)函數(shù)在運行時可調(diào)試,而宏定義不可以;
2.編譯器會對內(nèi)聯(lián)函數(shù)的參數(shù)類型做安全檢查或自動類型轉(zhuǎn)換(同普通函數(shù)),而宏定義則不會;
3.內(nèi)聯(lián)函數(shù)可以訪問類的成員變量,宏定義則不能;
4.在類中聲明同時定義的成員函數(shù),自動轉(zhuǎn)化為內(nèi)聯(lián)函數(shù)。
C++ 語言的函數(shù)內(nèi)聯(lián)機(jī)制既具備宏代碼的效率,又增加了安全性,而且可以自由操作類的數(shù)據(jù)成員。所以在C++ 程序中,應(yīng)該用內(nèi)聯(lián)函數(shù)取代所有宏代碼
一個可執(zhí)行文件的cpp文件中一個函數(shù)只能被定義一次。如果你把函數(shù)定義在一個.h文件中并讓兩個cpp包含就會造成這個函數(shù)分別在兩個cpp中被定義產(chǎn)生錯誤。但是inline函數(shù)是允許在多個cpp中多次定義的,就解決了這個問題。
for (int i=v.begin() ; i<v.size() ; i++) { .... }
對于size()的調(diào)用,其實是內(nèi)聯(lián)。在循環(huán)時,可以采用變量保存v.size()的值,以減少每個循環(huán)的調(diào)用開支。于是決定一搜,順便總結(jié)之。
1、inline的引出
考慮下列min()函數(shù)
int min( int v1, int v2 ) { return( v1 < v2 << v1 : v2 ); }
為這樣的小操作定義一個函數(shù)的好處是:
a.如果一段代碼包含min()的調(diào)用,那閱讀這樣的代碼并解釋其含義比讀一個條件操作符的實例,可讀性會強(qiáng)很多。
b.改變一個局部化的實現(xiàn)比更改一個應(yīng)用中的300個出現(xiàn)要容易得多
c.語義是統(tǒng)一的,每個測試都能保證相同的方式實現(xiàn)
d.函數(shù)可以被重用,不必為其他的應(yīng)用重寫代碼
不過,將min()寫成函數(shù)有一個嚴(yán)重的缺點:調(diào)用函數(shù)比直接計算條件操作符要慢很多。那怎么能兼顧以上優(yōu)點和效率呢?C++提供的解決方案為inline(內(nèi)聯(lián))函數(shù)
2、inline的原理:代碼替代
在程序編譯時,編譯器將程序中出現(xiàn)的內(nèi)聯(lián)函數(shù)的調(diào)用表達(dá)式用內(nèi)聯(lián)函數(shù)的函數(shù)體來進(jìn)行替代。
例如,如果一個函數(shù)被指定為inline 函數(shù)則它將在程序中每個調(diào)用點上被內(nèi)聯(lián)地展開例如
int minVal2 = min( i, j );
在編譯時被展開為
int minVal2 = i < j << i : j;
則把min()寫成函數(shù)的額外執(zhí)行開銷從而被消除了。
3、inline的使用
讓一個函數(shù)成為內(nèi)聯(lián)函數(shù),隱式的為在類里定義函數(shù),顯式的則是在函數(shù)前加上inline關(guān)鍵字說明。
4、使用inline的一些注意事項
a.從inline的原理,我們可以看出,inline的原理,是用空間換取時間的做法,是以代碼膨脹(復(fù)制)為代價,僅僅省去了函數(shù)調(diào)用的開銷,從而提高函數(shù)的執(zhí)行效率。如果執(zhí)行函數(shù)體內(nèi)代碼的時間,相比于函數(shù)調(diào)用的開銷較大,那么效率的收獲會很少。所以,如果函數(shù)體代碼過長或者函數(shù)體重有循環(huán)語句,if語句或switch語句或遞歸時,不宜用內(nèi)聯(lián)
b.關(guān)鍵字inline 必須與函數(shù)定義體放在一起才能使函數(shù)成為內(nèi)聯(lián),僅將inline 放在函數(shù)聲明前面不起任何作用。內(nèi)聯(lián)函數(shù)調(diào)用前必須聲明。
inline void Foo(int x, int y); // inline 僅與函數(shù)聲明放在一起 void Foo(int x, int y) { ... }
以上代碼不能成為內(nèi)聯(lián)函數(shù),而以下則可以
void Foo(int x, int y); inline void Foo(int x, int y) // inline 與函數(shù)定義體放在一起 { ... }
所以說,inline 是一種“用于實現(xiàn)的關(guān)鍵字”,而不是一種“用于聲明的關(guān)鍵字”。對于以上例子,林銳還建議,只在定義前加上inline,而不是在聲明和定義前都加,因為這能體現(xiàn)高質(zhì)量C++/C 程序設(shè)計風(fēng)格的一個基本原則:聲明與定義不可混為一談。
c.inline對于編譯器來說只是一個建議,編譯器可以選擇忽略該建議。換句話說,哪怕真的寫成了inline,也沒有任何錯誤的情況下,編譯器會自動進(jìn)行優(yōu)化。所以當(dāng)inline中出現(xiàn)了遞歸,循環(huán),或過多代碼時,編譯器自動無視inline聲明,同樣作為普通函數(shù)調(diào)用。
總結(jié)下:
覺得可以將內(nèi)聯(lián)理解為C++中對于函數(shù)專有的宏,對于C的函數(shù)宏的一種改進(jìn)。對于常量宏,C++提供const替代;而對于函數(shù)宏,C++提供的方案則是inline。在C中,大家都知道宏的優(yōu)勢,編譯器通過復(fù)制宏代碼的方式,省去了參數(shù)壓棧,生成匯編的call調(diào)用,返回參數(shù)等操作,雖然存在一些安全隱患,但在效率上,還是很可取的。
不過函數(shù)宏還是有不少缺陷的,主要有以下:
a.在復(fù)制代碼時,容易出現(xiàn)一想不到的邊際效應(yīng),比如經(jīng)典的
#define MAX(a, b) (a) > (b) ? (a) : (b)
在執(zhí)行語句:
result = MAX(i, j) + 2 ;
時,會被解釋為
result = (i) > (j) ? (i) : (j) + 2 ;
b.使用宏,無法進(jìn)行調(diào)試,雖然windows提供了ASSERT宏
c.使用宏,無法訪問類的私有成員
所以,C++ 通過內(nèi)聯(lián)機(jī)制,既具備宏代碼的效率,又增加了安全性,還可以自由操作類的數(shù)據(jù)成員,算是一個比較完美的解決方案。
相關(guān)文章
C++迭代器介紹(iterator、const_iterator、reverse_interator、const_rev
這篇文章主要介紹了C++迭代器介紹(iterator、const_iterator、reverse_interator、const_reverse_interator),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02Opencv基于CamShift算法實現(xiàn)目標(biāo)跟蹤
這篇文章主要為大家詳細(xì)介紹了Opencv基于CamShift算法實現(xiàn)目標(biāo)跟蹤,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01C++數(shù)據(jù)結(jié)構(gòu)之哈希算法詳解
這篇文章主要為大家詳細(xì)介紹了C++數(shù)據(jù)結(jié)構(gòu)中哈希算法的相關(guān)資料,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,希望對大家有所幫助2022-12-12C++ Boost Serialization庫超詳細(xì)獎金額
Boost是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱。Boost庫是一個可移植、提供源代碼的C++庫,作為標(biāo)準(zhǔn)庫的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開發(fā)引擎之一,是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱2022-12-12