[原創(chuàng)文章歡迎轉(zhuǎn)載,但請(qǐng)保留作者信息] Justin 于 2010-01-04
使用內(nèi)聯(lián)函數(shù)(inline function)可以省去一般函數(shù)調(diào)用的入棧操作開銷,比宏(macro)要好用。從編譯器的角度來(lái)看,沒(méi)有函數(shù)調(diào)用的代碼要更容易優(yōu)化。 但是天下沒(méi)有免費(fèi)的午餐,以空間換時(shí)間的內(nèi)聯(lián)函數(shù)同時(shí)也帶來(lái)了更大的程序占用空間,更甚者還會(huì)因?yàn)檫@變大的代碼空間導(dǎo)致額外的內(nèi)存換頁(yè)操作,降低指令緩存(instruction cache)的命中率……這些都是使用內(nèi)聯(lián)函數(shù)需要考慮到的負(fù)面影響。(Scott還是辯證地提醒了一點(diǎn):當(dāng)內(nèi)聯(lián)函數(shù)非常短小時(shí),相比一般意義上的函數(shù)調(diào)用,它能夠幫助編譯器生成更小的最終代碼和運(yùn)行時(shí)更高的指令緩存命中率)
內(nèi)聯(lián)函數(shù)的聲明可以是顯式的:使用inline關(guān)鍵字;也可以是隱式的:在類的定義中定義函數(shù)。
內(nèi)聯(lián)函數(shù)一般而言都是定義在頭文件中,這是因?yàn)榇蠖鄶?shù)編譯器的內(nèi)聯(lián)動(dòng)作都是發(fā)生在編譯過(guò)程中。(也有著鏈接甚至是運(yùn)行中才進(jìn)行內(nèi)聯(lián)的,但是俺們這里隨大流,講主要矛盾) 雖然內(nèi)聯(lián)函數(shù)和函數(shù)模板有一點(diǎn)相似:它們都幾乎定義在頭文件中,但是這兩者之間沒(méi)有必然聯(lián)系,而非有的程序員想的那樣“函數(shù)模板一定是內(nèi)聯(lián)的”)
另外一點(diǎn)容易被初學(xué)者忽視的是,內(nèi)聯(lián)函數(shù)的定義僅僅是對(duì)編譯器提出內(nèi)聯(lián)的請(qǐng)求。編譯器完全有可能忽視這個(gè)請(qǐng)求,于是某“內(nèi)聯(lián)函數(shù)”有可能在最后還是生成了一般函數(shù)的代碼。在這個(gè)情況下編譯器很有可能是對(duì)的:
-
請(qǐng)求內(nèi)聯(lián)的函數(shù)有可能太過(guò)于復(fù)雜
-
請(qǐng)求內(nèi)聯(lián)的函數(shù)有可能是虛函數(shù)(虛函數(shù)的真正實(shí)體要在運(yùn)行時(shí)才能得知,讓編譯器編譯階段去做內(nèi)聯(lián)實(shí)在有點(diǎn)強(qiáng)人所難)
-
請(qǐng)求內(nèi)聯(lián)的函數(shù)沒(méi)什么問(wèn)題,但是在代碼中有用函數(shù)指針的方式調(diào)用該函數(shù)(這樣編譯器也沒(méi)辦法,如果不生成一般函數(shù)哪來(lái)的函數(shù)指針?)
這些情況下確實(shí)不應(yīng)該把函數(shù)作為內(nèi)聯(lián)函數(shù)。一個(gè)“內(nèi)聯(lián)函數(shù)”是否最終生成了內(nèi)聯(lián)函數(shù),還得編譯器說(shuō)了算。 然而編譯器并不是總能幫助我們做出正確的決定,還有一些情況是需要我們自己做出判斷的:
-
請(qǐng)求內(nèi)聯(lián)的函數(shù)是構(gòu)造/析構(gòu)函數(shù)(表面上看起來(lái)某個(gè)構(gòu)造/析構(gòu)函數(shù)很短小甚至是空的,但是為了構(gòu)造/析構(gòu)類中的其他成員,編譯器有可能會(huì)“自覺(jué)”地寫入必要的代碼,這樣的構(gòu)造/析構(gòu)函數(shù)就有可能不適合再做內(nèi)聯(lián)了)這一點(diǎn)原文中有更詳細(xì)的說(shuō)明。
-
當(dāng)編寫支持庫(kù)時(shí)(library)也不建議使用內(nèi)聯(lián)函數(shù),因?yàn)橐坏┯脩羰褂昧诉@些含有內(nèi)聯(lián)函數(shù)的庫(kù)并編譯了自己的程序,這些內(nèi)聯(lián)函數(shù)就已經(jīng)“寫死”在他們的程序中了。當(dāng)日后對(duì)原先的庫(kù)做了更新修改,用戶就必須重新編譯整個(gè)程序才能用上新的補(bǔ)丁。而一般的函數(shù)就不會(huì)有這個(gè)問(wèn)題:他們是動(dòng)態(tài)鏈接的,用戶根本感覺(jué)不到任何改動(dòng)。
-
考慮到很多調(diào)試器(debugger)無(wú)法調(diào)試內(nèi)聯(lián)函數(shù)(本來(lái)就沒(méi)有這么一個(gè)“函數(shù)”,叫人家怎么設(shè)斷點(diǎn)?),在調(diào)試版本中也不建議使用內(nèi)聯(lián)函數(shù)。
有那么多需要注意的地方,大師最后總結(jié)了一下:用好內(nèi)聯(lián)函數(shù)的第一步就是:不用內(nèi)聯(lián)函數(shù)。并沒(méi)有那么多的函數(shù)真正需要內(nèi)聯(lián),因?yàn)?0%的程序運(yùn)行時(shí)間都是花在了20%的代碼中。第二步是把內(nèi)聯(lián)函數(shù)當(dāng)成是手工優(yōu)化的手段,僅僅在非常需要效率和優(yōu)化的代碼中使用內(nèi)聯(lián)。
|