C++深入探索內(nèi)聯(lián)函數(shù)inline與auto關(guān)鍵字的使用
1.內(nèi)斂函數(shù)
1.1問題引入
我們?cè)谑褂肅語言中我們都學(xué)過函數(shù),我們知道函數(shù)在調(diào)用的過程中需要開辟棧幀。如果我們需要頻繁的調(diào)用一個(gè)函數(shù),假設(shè)我們調(diào)用10次Add()函數(shù),那我們就需要建立10次棧幀。我們都知道在棧幀中要做很多事情,例如保存寄存器,壓參數(shù),壓返回值等等,這個(gè)過程是很麻煩的。那在C語言中,我們可以通過宏來解決這個(gè)問題。在C++中,我們便引入了內(nèi)斂函數(shù)(inline)。
1.2內(nèi)聯(lián)函數(shù)的概念
以inline修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時(shí)C++編譯器會(huì)在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開,沒有函數(shù)壓棧的開銷,內(nèi)聯(lián)函數(shù)提升程序運(yùn)行的效率。
我們這里依然使用Add()函數(shù)舉例。這段代碼是我們常寫的Add()函數(shù)。假設(shè)我們多次調(diào)用Add函數(shù),在C語言中,我們可以使用宏替換。在C++我們可以在函數(shù)前加上inline
int Add(int x, int y) { int z = x + y; return z; }
C語言中用宏來代替Add函數(shù):
#define Add(x,y) ((x)+(y))
C++中在函數(shù)前加上inline使之成為內(nèi)聯(lián)函數(shù)
inline int Add(int x, int y) { int z = x + y; return z; }
那C語言已經(jīng)有了宏替換,為什么C++還要出現(xiàn)內(nèi)聯(lián)函數(shù)呢?
主要是有兩個(gè)原因:
1.宏晦澀難懂不好控制,特別容易寫錯(cuò).語法機(jī)制設(shè)計(jì)不好。
2.宏不支持調(diào)試,但是內(nèi)斂在debug下支持調(diào)試(在debug下不會(huì)展開,在release下才會(huì)展開),這樣我們對(duì)代碼的理解和掌握將大大提高。
如果在Add函數(shù)前增加 inline 關(guān)鍵字將其改成內(nèi)聯(lián)函數(shù),在編譯期間編譯器會(huì)用函數(shù)體替換函數(shù)的調(diào)用。 查看方式:
1. 在 release 模式下,查看編譯器生成的匯編代碼中是否存在 call Add
2. 在 debug 模式下,需要對(duì)編譯器進(jìn)行設(shè)置,否則不會(huì)展開 ( 因?yàn)?debug 模式下,編譯器默認(rèn)不會(huì)對(duì)代碼進(jìn) 行優(yōu)化,以下給出 vs2019 的設(shè)置方式 )
1.3內(nèi)斂函數(shù)的特性
1. inline 是一種 以空間換時(shí)間 的做法,省去調(diào)用函數(shù)額開銷。所以 代碼很長 或者有 循環(huán) / 遞歸 的函數(shù)不適宜使用作為內(nèi)聯(lián)函數(shù)。
2. inline 對(duì)于編譯器而言只是一個(gè)建議 ,編譯器會(huì)自動(dòng)優(yōu)化,如果定義為 inline 的函數(shù)體內(nèi)有循環(huán) / 遞歸等等,編譯器優(yōu)化時(shí)會(huì)忽略掉內(nèi)聯(lián)。
3. inline 不建議聲明和定義分離,分離會(huì)導(dǎo)致鏈接錯(cuò)誤。因?yàn)?inline 被展開,就沒有函數(shù)地址了,鏈接就會(huì)找不到
- inline是一種以空間換時(shí)間的做法,省去調(diào)用函數(shù)額開銷(建立棧幀).所以代碼很長或者遞歸的函數(shù)不適宜用內(nèi)聯(lián)函數(shù).
這里代碼多長算長呢? 一般是10行左右,具體取決于編譯器。
- inline對(duì)于編譯器而言只是一個(gè)建議,編譯器會(huì)自動(dòng)優(yōu)化,如果定義為inline的函數(shù)體內(nèi)有循環(huán)/遞歸等等,編譯器優(yōu)化時(shí)會(huì)忽略掉內(nèi)聯(lián)。
這里可以舉個(gè)例子,假設(shè)我們有一個(gè)代碼需要10行,但是我們需要調(diào)用1000次。如果inline替換的話,我們要有1000*10條指令,如果不替換則有1000+10條指令。因此最終是否替換,取決于編譯器。
inline int Add(int x, int y) { int z = x + y; z += x * y; z += x * y; z += x * y; z += x * y; z += x * y; z += x * y; z += x * y; z += x * y; z += x * y; z += x * y; z += x * y; return z; }
我們發(fā)現(xiàn),雖然Add函數(shù)前加了inline,但是最終卻沒有展開。
- inline不建議聲明和定義分離,分離會(huì)導(dǎo)致鏈接錯(cuò)誤。因?yàn)閕nline被展開,就沒有函數(shù)地址了,鏈接就會(huì)找不到
我們?cè)趂.cpp中調(diào)用一下:發(fā)現(xiàn)報(bào)錯(cuò)了
在這里他就會(huì)發(fā)生鏈接錯(cuò)誤:
這是因?yàn)閠est.h中替換到test.cpp中發(fā)現(xiàn)是內(nèi)聯(lián)函數(shù),內(nèi)聯(lián)函數(shù)不需要生成地址,因?yàn)閮?nèi)聯(lián)函數(shù)調(diào)用的地方都展開了,因此不會(huì)存在在符號(hào)表中。外部調(diào)用時(shí)就找不到。因此不要將聲明和定義分開。
2.auto關(guān)鍵字
2.1 auto簡介
在早期 C/C++ 中 auto 的含義是:使用 auto 修飾的變量,是具有自動(dòng)存儲(chǔ)器的局部變量。C++11中,標(biāo)準(zhǔn)委員會(huì)賦予了auto 全新的含義即: auto 不再是一個(gè)存儲(chǔ)類型指示符,而是作為一個(gè)新的類型 指示符來指示編譯器, auto 聲明的變量必須由編譯器在編譯時(shí)期推導(dǎo)而得
auto在C語言中我們是接觸過的:最寬宏大量的關(guān)鍵字,由于局部變量默認(rèn)都是auto修飾的,因此auto可以省略,這就導(dǎo)致auto常常被人忽略。那么在C++11中,auto進(jìn)行了升級(jí),有了新的功能--自動(dòng)推導(dǎo)。(注意:auto新功能只是在C++11之后才有此功能)
那么auto是怎么自動(dòng)推導(dǎo)呢?
我們可以使用typeid,來打印一個(gè)變量的類型。
int main() { const int a = 10; auto b = &a; auto c = 'a'; cout << typeid(b).name() << endl;//typeid可以打印一個(gè)變量的類型 cout << typeid(a).name() << endl;//typeid可以打印一個(gè)變量的類型 cout << typeid(c).name() << endl;//typeid可以打印一個(gè)變量的類型 return 0; }
我們發(fā)現(xiàn)auto的自動(dòng)推導(dǎo)還是很智能的。
auto意義之一:類型很長時(shí),懶得寫,可以讓他自動(dòng)推導(dǎo)
注意:
使用 auto 定義變量時(shí)必須對(duì)其進(jìn)行初始化,在編譯階段編譯器需要根據(jù)初始化表達(dá)式來推導(dǎo) auto 的實(shí)際類 型 。因此 auto 并非是一種 “ 類型 ” 的聲明,而是一個(gè)類型聲明時(shí)的 “ 占位符 ” ,編譯器在編譯期會(huì)將 auto 替換為 變量實(shí)際的類型 。
2.2 auto的使用細(xì)則
1. auto與指針和引用結(jié)合起來使用auto聲明指針類型時(shí),用auto和auto*沒有任何區(qū)別,但用auto聲明引用類型時(shí)則必須加&.
int main() { int x = 10; auto a = &x; auto& c = x; cout << typeid(x).name() << endl;//typeid可以打印一個(gè)變量的類型 cout << typeid(a).name() << endl;//typeid可以打印一個(gè)變量的類型 cout << typeid(c).name() << endl;//typeid可以打印一個(gè)變量的類型 return 0; }
2. 在同一行定義多個(gè)變量當(dāng)在同一行聲明多個(gè)變量時(shí),這些變量必須是相同的類型,否則編譯器將會(huì)報(bào)錯(cuò),因?yàn)榫幾g器實(shí)際只對(duì)第一個(gè)類型進(jìn)行推導(dǎo),然后用推導(dǎo)出來的類型定義其他變量。
auto a = 1, b = 2; auto c = 3, d = 4.0;//c和d類型不同,auto推導(dǎo)會(huì)沖突的
2.3 auto不能推導(dǎo)的場景
1. auto不能作為函數(shù)的參數(shù)
// 此處代碼編譯失敗,auto不能作為形參類型,因?yàn)榫幾g器無法對(duì)a的實(shí)際類型進(jìn)行推導(dǎo) void TestAuto(auto a) {}
2. auto不能直接用來聲明數(shù)組
void TestAuto() { int a[] = { 1,2,3 }; auto b[] = { 4,5,6 }; }
2.4 auto與新式for循環(huán)使用
在平常我們打印一個(gè)array數(shù)組,我們需要依次打印遍歷。如下代碼所示:
int main() { int array[] = { 1,2,3,4,5 }; for (int i = 0; i < sizeof(array) / sizeof(int); ++i) array[i] *= 2; for (int i = 0; i < sizeof(array) / sizeof(int); ++i) cout << array[i] << " "; cout << endl; return 0; }
我們也可以使用auto結(jié)合范圍for循環(huán)打印這個(gè)數(shù)組:
for (auto e : array) cout << e << " "; cout << endl;
在這里我們使用到了一個(gè)新的for循環(huán),范圍for。它會(huì)依次自動(dòng)取array中的數(shù)據(jù),賦值給e,并且會(huì)自動(dòng)判斷結(jié)束,因此我們使用auto可以自動(dòng)識(shí)別數(shù)組元素的類型。
注意:e只是array的拷貝,改變e不會(huì)改變array數(shù)組的內(nèi)容。如果我們想改變array的內(nèi)容,只需要加個(gè)引用即可,意思是讓e成為array的別名,代碼如下:
//加個(gè)引用就可以訪問到array for (auto& e : array) { e /= 2; } for (auto e : array) cout << e << " ";
到此這篇關(guān)于C++深入探索內(nèi)聯(lián)函數(shù)inline與auto關(guān)鍵字的使用的文章就介紹到這了,更多相關(guān)C++ inline與auto內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Qt出現(xiàn)假死凍結(jié)現(xiàn)象的原因及解決方法
應(yīng)用程序出現(xiàn)假死或凍結(jié)現(xiàn)象通常是由于一些常見問題所導(dǎo)致的,本文主要介紹了Qt出現(xiàn)假死凍結(jié)現(xiàn)象的原因及解決方法,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10C++ 實(shí)現(xiàn)稀疏矩陣的壓縮存儲(chǔ)的實(shí)例
這篇文章主要介紹了C++ 實(shí)現(xiàn)稀疏矩陣的壓縮存儲(chǔ)的實(shí)例的相關(guān)資料,M*N的矩陣,矩陣中有效值的個(gè)數(shù)遠(yuǎn)小于無效值的個(gè)數(shù),且這些數(shù)據(jù)的分布沒有規(guī)律,需要的朋友可以參考下2017-07-07C++優(yōu)先級(jí)隊(duì)列的使用指南與模擬實(shí)現(xiàn)
優(yōu)先級(jí)隊(duì)列是一種特殊的隊(duì)列,其中每個(gè)元素都有一個(gè)與之關(guān)聯(lián)的優(yōu)先級(jí),優(yōu)先級(jí)較高的元素會(huì)在隊(duì)列中較早地被處理,而優(yōu)先級(jí)較低的元素會(huì)在后續(xù)處理,本文給大家介紹C++優(yōu)先級(jí)隊(duì)列的使用指南與模擬實(shí)現(xiàn),需要的朋友可以參考下2023-09-09深入理解C++的動(dòng)態(tài)綁定與靜態(tài)綁定的應(yīng)用詳解
本篇文章是對(duì)C++中的動(dòng)態(tài)綁定與靜態(tài)綁定進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05總結(jié)C/C++面試中可能會(huì)碰到的字符串指針題
C/C++是最能體現(xiàn)程序員能力的語言之一,其功能強(qiáng)大,在IT行業(yè)的各個(gè)方面都有大量的應(yīng)用。下面這篇文章主要介紹了總結(jié)了在C/C++面試中可能會(huì)碰到的字符串指針題,需要的朋友可以參考借鑒,下面來一起看看吧。2017-01-01一起來學(xué)習(xí)C語言的程序環(huán)境與預(yù)處理
這篇文章主要為大家詳細(xì)介紹了C語言程序環(huán)境與預(yù)處理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-03-03