C/C++編程筆記:C++特性丨內(nèi)聯(lián)函數(shù),及其詳細(xì)解釋

內(nèi)聯(lián)函數(shù)是C ++的重要特性之一。那么,讓我們首先了解為什么使用內(nèi)聯(lián)函數(shù),以及內(nèi)聯(lián)函數(shù)的目的是什么?

當(dāng)程序執(zhí)行函數(shù)調(diào)用指令時(shí),CPU將存儲(chǔ)該函數(shù)調(diào)用之后的指令的內(nèi)存地址,將函數(shù)的參數(shù)復(fù)制到堆棧上,最后將控制權(quán)轉(zhuǎn)移到指定的函數(shù)。然后,CPU執(zhí)行功能代碼,將功能返回值存儲(chǔ)在預(yù)定義的存儲(chǔ)位置/寄存器中,并將控制權(quán)返回給調(diào)用函數(shù)。如果函數(shù)的執(zhí)行時(shí)間少于從調(diào)用者函數(shù)到被調(diào)用函數(shù)(被調(diào)用者)的切換時(shí)間,則這可能會(huì)成為開銷。
對(duì)于大型函數(shù)和/或執(zhí)行復(fù)雜任務(wù)的函數(shù),與函數(shù)運(yùn)行所花費(fèi)的時(shí)間相比,函數(shù)調(diào)用的開銷通常是微不足道的。但是,對(duì)于小型的常用功能,進(jìn)行函數(shù)調(diào)用所需的時(shí)間通常比實(shí)際執(zhí)行函數(shù)代碼所需的時(shí)間多得多。對(duì)于小型功能,會(huì)發(fā)生這種開銷,因?yàn)樾⌒凸δ艿膱?zhí)行時(shí)間小于切換時(shí)間。
C ++提供了一個(gè)內(nèi)聯(lián)函數(shù),以減少函數(shù)調(diào)用的開銷。內(nèi)聯(lián)函數(shù)是在調(diào)用時(shí)在行中擴(kuò)展的函數(shù)。調(diào)用內(nèi)聯(lián)函數(shù)時(shí),將在內(nèi)聯(lián)函數(shù)調(diào)用時(shí)插入或替換內(nèi)聯(lián)函數(shù)的整個(gè)代碼。此替換由C ++編譯器在編譯時(shí)執(zhí)行。如果內(nèi)聯(lián)函數(shù)很小,則可以提高效率。
定義函數(shù)內(nèi)聯(lián)的語(yǔ)法為:
內(nèi)聯(lián)返回類型函數(shù)名稱(參數(shù)){
?//功能代碼
}
請(qǐng)記住,內(nèi)聯(lián)只是對(duì)編譯器的請(qǐng)求,而不是命令。編譯器可以忽略內(nèi)聯(lián)請(qǐng)求。在以下情況下,編譯器可能不會(huì)執(zhí)行內(nèi)聯(lián):
1)如果函數(shù)包含循環(huán)。(對(duì)于while,do-while)
2)如果函數(shù)包含靜態(tài)變量。
3)如果函數(shù)是遞歸的。
4)如果函數(shù)的返回類型不是void,并且return語(yǔ)句在函數(shù)體中不存在。
5)如果函數(shù)包含switch或goto語(yǔ)句。
內(nèi)聯(lián)函數(shù)具有以下優(yōu)點(diǎn):
1)不會(huì)發(fā)生函數(shù)調(diào)用開銷。
2)調(diào)用函數(shù)時(shí),還可以節(jié)省堆棧中push / pop變量的開銷。
3)它還節(jié)省了從函數(shù)返回調(diào)用的開銷。
4)內(nèi)聯(lián)函數(shù)時(shí),可以使編譯器對(duì)函數(shù)主體執(zhí)行特定于上下文的優(yōu)化。對(duì)于普通的函數(shù)調(diào)用來(lái)說(shuō),這樣的優(yōu)化是不可能的。通過(guò)考慮調(diào)用上下文和被調(diào)用上下文的流程可以獲得其他優(yōu)化。
5)內(nèi)聯(lián)函數(shù)可能對(duì)于嵌入式系統(tǒng)很有用(如果很?。?,因?yàn)閮?nèi)聯(lián)函數(shù)所產(chǎn)生的代碼少于函數(shù)調(diào)用的前導(dǎo)和返回。
內(nèi)聯(lián)函數(shù)的缺點(diǎn):
1)內(nèi)聯(lián)函數(shù)中添加的變量消耗了額外的寄存器,在內(nèi)聯(lián)函數(shù)之后,如果要使用寄存器的變量編號(hào)增加,則它們可能會(huì)增加寄存器變量資源利用的開銷。這意味著當(dāng)在函數(shù)調(diào)用點(diǎn)替換內(nèi)聯(lián)函數(shù)主體時(shí),該函數(shù)使用的變量總數(shù)也會(huì)被插入。因此,將用于變量的寄存器數(shù)量也將增加。因此,如果函數(shù)內(nèi)聯(lián)后的變量數(shù)急劇增加,則肯定會(huì)導(dǎo)致寄存器利用率增加。
2)如果使用太多的內(nèi)聯(lián)函數(shù),則由于重復(fù)執(zhí)行相同的代碼,因此二進(jìn)制可執(zhí)行文件的大小將很大。
3)過(guò)多的內(nèi)聯(lián)也會(huì)降低指令高速緩存命中率,從而降低了從高速緩存到主存儲(chǔ)器的指令獲取速度。
4)如果有人更改了內(nèi)聯(lián)函數(shù)中的代碼,則內(nèi)聯(lián)函數(shù)可能會(huì)增加編譯時(shí)間開銷,然后必須重新編譯所有調(diào)用位置,因?yàn)榫幾g器將需要再次替換所有代碼以反映更改,否則它將繼續(xù)使用舊功能。
5)內(nèi)聯(lián)函數(shù)對(duì)于許多嵌入式系統(tǒng)可能沒(méi)有用。因?yàn)樵谇度胧较到y(tǒng)中,代碼大小比速度更重要。
6)內(nèi)聯(lián)函數(shù)可能會(huì)導(dǎo)致崩潰,因?yàn)閮?nèi)聯(lián)可能會(huì)增加二進(jìn)制可執(zhí)行文件的大小。內(nèi)存溢出會(huì)導(dǎo)致計(jì)算機(jī)性能下降。
下面的程序演示了如何使用內(nèi)聯(lián)函數(shù)。

內(nèi)聯(lián)函數(shù)和類:
也可以在類內(nèi)部定義內(nèi)聯(lián)函數(shù)。實(shí)際上,該類內(nèi)部定義的所有函數(shù)都是隱式內(nèi)聯(lián)的。因此,這里也適用所有內(nèi)聯(lián)函數(shù)的限制。如果您需要在類中顯式聲明內(nèi)聯(lián)函數(shù),則只需在類內(nèi)部聲明該函數(shù),然后使用inline關(guān)鍵字在類外對(duì)其進(jìn)行定義。
例如:

上面的樣式被認(rèn)為是不好的編程樣式。最好的編程風(fēng)格是只在類內(nèi)部編寫函數(shù)的原型,并將其指定為函數(shù)定義中的內(nèi)聯(lián)。
例如:

下面的程序演示了此概念:


輸出:
Enter first value: 45
Enter second value: 15
Addition of two numbers: 60
Difference of two numbers: 30
Product of two numbers: 675
Division of two numbers: 3
宏有什么問(wèn)題?
熟悉C語(yǔ)言的讀者知道C語(yǔ)言使用宏。預(yù)處理程序直接在宏代碼內(nèi)替換所有宏調(diào)用。建議始終使用內(nèi)聯(lián)函數(shù)而不是宏。據(jù)C ++的創(chuàng)建者Bjarne Stroustrup博士說(shuō),在C ++中,宏幾乎從不需要,而且容易出錯(cuò)。在C ++中使用宏存在一些問(wèn)題。宏無(wú)法訪問(wèn)班級(jí)的私人成員。宏看起來(lái)像函數(shù)調(diào)用,但實(shí)際上不是。
例子:

C ++編譯器檢查內(nèi)聯(lián)函數(shù)的參數(shù)類型,并且正確執(zhí)行了必要的轉(zhuǎn)換。預(yù)處理程序宏無(wú)法執(zhí)行此操作。另一件事是,宏由預(yù)處理器管理,內(nèi)聯(lián)函數(shù)由C ++編譯器管理。
切記:確實(shí),該類內(nèi)部定義的所有函數(shù)都是隱式內(nèi)聯(lián)的,并且C ++編譯器將對(duì)這些函數(shù)執(zhí)行內(nèi)聯(lián)調(diào)用,但是如果該函數(shù)是虛擬的,則C ++編譯器將無(wú)法執(zhí)行內(nèi)聯(lián)。原因是對(duì)虛擬函數(shù)的調(diào)用是在運(yùn)行時(shí)而不是在編譯時(shí)解決的。虛擬方式要等到運(yùn)行時(shí)才進(jìn)行,而內(nèi)聯(lián)方式要等到編譯期間,如果編譯器不知道將調(diào)用哪個(gè)函數(shù),它如何執(zhí)行內(nèi)聯(lián)?
要記住的另一件事是,僅當(dāng)函數(shù)調(diào)用期間花費(fèi)的時(shí)間比函數(shù)主體執(zhí)行時(shí)間多時(shí),才使函數(shù)內(nèi)聯(lián)是有用的。內(nèi)聯(lián)函數(shù)完全無(wú)效的示例:
inlinevoidshow()
{
????cout << "value of S = "<< S << endl;
}
上面的函數(shù)執(zhí)行起來(lái)相對(duì)要花很長(zhǎng)時(shí)間。通常,不應(yīng)將執(zhí)行輸入輸出(I / O)操作的功能定義為內(nèi)聯(lián)函數(shù),因?yàn)樗鼤?huì)花費(fèi)大量時(shí)間。從技術(shù)上講,show()函數(shù)的內(nèi)聯(lián)值是有限的,因?yàn)镮 / O語(yǔ)句將花費(fèi)的時(shí)間遠(yuǎn)遠(yuǎn)超過(guò)了函數(shù)調(diào)用的開銷。
如果函數(shù)沒(méi)有內(nèi)聯(lián)擴(kuò)展,則取決于使用的編譯器,編譯器可能會(huì)向您顯示警告。像Java和C#這樣的編程語(yǔ)言不支持內(nèi)聯(lián)函數(shù)。
但是在Java中,編譯器可以在調(diào)用小型final方法時(shí)執(zhí)行內(nèi)聯(lián),因?yàn)閒inal方法不能被子類覆蓋,并且對(duì)final方法的調(diào)用在編譯時(shí)就可以解決。在C#中,JIT編譯器還可以通過(guò)內(nèi)聯(lián)小型函數(shù)調(diào)用來(lái)優(yōu)化代碼(例如,在循環(huán)中替換小型函數(shù)的主體)。
最后要記住的是,內(nèi)聯(lián)函數(shù)是C ++的寶貴功能。適當(dāng)?shù)厥褂脙?nèi)聯(lián)函數(shù)可以提高性能,但是如果任意使用內(nèi)聯(lián)函數(shù),則它們無(wú)法提供更好的結(jié)果。換句話說(shuō),不要指望程序有更好的性能。不要使每個(gè)函數(shù)都內(nèi)聯(lián)。最好使內(nèi)聯(lián)函數(shù)盡可能小。
以上。
每天學(xué)點(diǎn)小知識(shí),希望對(duì)你有幫助~
另外如果你想更好的提升你的編程能力,學(xué)好C語(yǔ)言C++編程!彎道超車,快人一步!筆者這里或許可以幫到你~

分享(源碼、項(xiàng)目實(shí)戰(zhàn)視頻、項(xiàng)目筆記,基礎(chǔ)入門教程)
歡迎轉(zhuǎn)行和學(xué)習(xí)編程的伙伴,利用更多的資料學(xué)習(xí)成長(zhǎng)比自己琢磨更快哦!