做移動網(wǎng)站優(yōu)化優(yōu)seo推廣代運營
1. 內(nèi)聯(lián)函數(shù)
1.1 C語言的宏
在C語言中,我們學(xué)習了用#define
定義的宏函數(shù),例如:
#define Add(x, y) ((x) + (y)) //兩數(shù)相加
相較于函數(shù),我們知道宏替換具有如下比較明顯的優(yōu)點:
- 性能優(yōu)勢: 宏在預(yù)處理階段進行簡單的文本替換,沒有函數(shù)調(diào)用的開銷,可以節(jié)省棧空間
- 靈活的參數(shù): 宏的參數(shù)可以是任意表達式,包括副作用表達式。這使得宏能夠以更靈活的方式進行代碼替換,可以處理一些復(fù)雜的操作。
但是,對應(yīng)的C語言的宏替換也有這些致命的缺陷:
- 不進行類型檢查: 宏在進行文本替換時不進行類型檢查,這可能導(dǎo)致一些潛在的類型錯誤。
- 沒有作用域: 宏在預(yù)處理階段進行文本替換,沒有作用域的概念。如果宏的名稱與其他標識符沖突,可能會導(dǎo)致錯誤或意外行為
- 不可隨意調(diào)試: 在調(diào)試過程中,很難對宏展開后的代碼進行單步調(diào)試,因為宏展開發(fā)生在預(yù)處理階段,調(diào)試器無法直接查看宏的展開結(jié)果。
注:如果想對C語言的宏有更深的了解,建議看看👉C語言——預(yù)處理
1.2 內(nèi)聯(lián)函數(shù)
而為了解決C語言#define
宏所帶來的缺陷,C++有了inline
關(guān)鍵字。
- 我們在函數(shù)的返回值類型前面加入
inline
關(guān)鍵字,這個函數(shù)就成為了內(nèi)聯(lián)函數(shù)。 - 內(nèi)聯(lián)函數(shù)會在編譯時被展開,從而避免了棧幀開銷。
- 同時,內(nèi)聯(lián)函數(shù)又具有函數(shù)的特性。因此具有類型檢查、作用域且方便調(diào)試。相較于宏函數(shù)更加安全。
- 可以說內(nèi)聯(lián)函數(shù)在具有宏函數(shù)優(yōu)點同時也完全解決了宏函數(shù)所帶來的缺陷。
例如:
inline void Func()
{printf("Hello World\n");
}int main()
{for (int i = 0; i < 100; i++)Func();return 0;
}
上面的代碼我們聲明了一個內(nèi)聯(lián)函數(shù)Func
,在編譯過后循環(huán)處的調(diào)用就會變成:
for (int i = 0; i < 100; i++)printf("Hello World\n"); //內(nèi)聯(lián)函數(shù)Func直接被展開成了函數(shù)體內(nèi)的內(nèi)容
1.2.1 通過反匯編查看內(nèi)聯(lián)函數(shù)的展開
以VS2019
為例:
首先,要用反匯編查看內(nèi)聯(lián)函數(shù)的展開,首先要對編譯器做如下設(shè)置:
-
首先,將
Debug模式
改為Release模式
-
然后,右擊項目名稱,點擊屬性
-
接著,配置屬性-> C/C++ -> 常規(guī) -> 調(diào)試信息格式 ->程序數(shù)據(jù)庫
- 最后,配置屬性-> C/C++ -> 優(yōu)化 -> 內(nèi)聯(lián)函數(shù)擴展 -> 只適用于
_inline
設(shè)置完成過后,我們就可以通過返匯編查看內(nèi)聯(lián)函數(shù)的展開了。
-
我們先來看看沒有加入
inline
關(guān)鍵字的普通函數(shù): -
再來看看加入
inline
關(guān)鍵字的內(nèi)聯(lián)函數(shù):
1.2.2 內(nèi)聯(lián)函數(shù)的局限性
既然內(nèi)聯(lián)函數(shù)可以避免棧幀開銷而且安全性也有保證,那是不是可以說以后我們可以將所有的函數(shù)都定義成內(nèi)聯(lián)函數(shù)呢?
當然不可以!!!
首先我們來看一組對比:
- 可以發(fā)現(xiàn),不是內(nèi)聯(lián)函數(shù)的文件空間比是內(nèi)聯(lián)函數(shù)的文件空間小了16KB
- 有小伙伴就會問了:不就十幾KB嘛,磁盤空間這么大不差這點。但是如果我將一個幾百行的函數(shù)也寫成一個內(nèi)聯(lián)函數(shù),那這二者之間占用空間的差距就不會這么小了。
所以我們有必要清楚內(nèi)聯(lián)函數(shù)的局限,知道什么時候可以用,什么時候不可以用;
- 通過上面的分析和比較可以知道,
inline
內(nèi)聯(lián)函數(shù)實際上是一種空間換時間的做法:通過代碼的展開來減少函數(shù)調(diào)用的開銷,但也因此導(dǎo)致了代碼膨脹的問題。 - 因此內(nèi)聯(lián)函數(shù)一般用作代碼簡短(不超過10行),經(jīng)常使用的函數(shù)。
- 而對于遞歸函數(shù)、存在大量循環(huán)的函數(shù)、存在
switch case
語句的函數(shù),一般不用inline
處理
1.2.3 內(nèi)聯(lián)函數(shù)的特性
如果有人不聽勸,將一個遞歸函數(shù)定義成內(nèi)聯(lián)函數(shù),會出現(xiàn)什么情況呢?
- 特性1:inline對于編譯器而言只是一個建議,不同編譯器關(guān)于inline實現(xiàn)機制可能不同,如果被定義的函數(shù)較為復(fù)雜,編譯器會
忽略inline特性
。 - 特性2:內(nèi)聯(lián)函數(shù)的聲明和定義最好不要分離,否則就只能在定義內(nèi)聯(lián)函數(shù)的文件中使用該內(nèi)聯(lián)函數(shù)
1.3 總結(jié)
inline
內(nèi)聯(lián)函數(shù)是C++專門針對C語言宏函數(shù)的缺陷而設(shè)計的。- 其既具有宏函數(shù)沒有函數(shù)調(diào)用開銷,所耗時間少的優(yōu)點;同時也基本上解決了宏函數(shù)不安全、難以調(diào)試的缺點。其功能不可謂不強。
- 然而內(nèi)聯(lián)函數(shù)也有較大的局限性:其只適用于代碼簡單、且頻繁調(diào)用的函數(shù)。而對于遞歸、有大量循環(huán)的函數(shù)則不適用。
- 內(nèi)聯(lián)函數(shù)只是對編譯器的一個建議,到底才不采用取決于編譯器。
- 內(nèi)聯(lián)函數(shù)的聲明和定義最好放在一起。