日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

inline内联的用法与作用

發(fā)布時(shí)間:2024/4/15 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 inline内联的用法与作用 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

inline內(nèi)聯(lián)的用法與作用

? ? ?內(nèi)聯(lián)函數(shù)是一種編譯機(jī)制,優(yōu)點(diǎn)從代碼上是看不出來(lái)的,但是程序的執(zhí)行效率上有差別,通常,編譯器對(duì)函數(shù)調(diào)用的處理是一種類似中斷的方式,即當(dāng)執(zhí)行到函數(shù)調(diào)用語(yǔ)句時(shí),程序把當(dāng)前所有的狀態(tài)信息比如CPU所有寄存器(其中一個(gè)很重要的就是指令指針寄存器)的值保存起來(lái),然后放心大膽地轉(zhuǎn)去執(zhí)行那個(gè)函數(shù)的代碼,執(zhí)行完后再返回原來(lái)的地方,恢復(fù)原先保存過(guò)的狀態(tài)信息,于是也就可以接著原來(lái)被中斷的指令繼續(xù)往下執(zhí)行。這樣,就很容易實(shí)現(xiàn)代碼的結(jié)構(gòu)化,因?yàn)榭梢园岩恍┆?dú)立的功能模塊寫成函數(shù),函數(shù)內(nèi)部的變量和外部的變量互不影響,而且函數(shù)執(zhí)行完后就可以釋放這個(gè)函數(shù)內(nèi)部變量的所使用的內(nèi)存空間(這就是為什么函數(shù)退出后,其內(nèi)部變量不再有效),對(duì)內(nèi)存的使用也是很經(jīng)濟(jì)的(否則,如果一個(gè)大的程序全部由一個(gè)函數(shù)組成,那么所有的變量都得自始至終地占用內(nèi)存空間),當(dāng)然,還有其他優(yōu)點(diǎn),比如可以實(shí)現(xiàn)遞歸,總之是好處多多。 ?
? ? ?可是,任何事情往往都有兩方面,這樣做雖然好處多多,但也是有代價(jià)的,那就是前面所說(shuō)的,任何一次函數(shù)調(diào)用,程序都得進(jìn)行保存和恢復(fù)狀態(tài)信息的動(dòng)作,用數(shù)據(jù)結(jié)構(gòu)的術(shù)語(yǔ)說(shuō)就是進(jìn)棧和退棧,當(dāng)然,還有內(nèi)存分配的過(guò)程,如果函數(shù)的代碼非常少,這種代價(jià)并不是可忽略的,比如說(shuō),你編寫一個(gè)類,里面有個(gè)記錄狀態(tài)的成員變量: ?
Class MyClass { private: int m_iState; } ? ? 按照面向?qū)ο蟮乃枷?#xff0c;函數(shù)的屬性應(yīng)盡量的私有化,但外部怎么獲得這個(gè)屬性值呢?一般的方法就是加一個(gè)共有函數(shù),這就實(shí)現(xiàn)的面向?qū)ο笏枷胫兴^“通過(guò)公用接口操作對(duì)象的私有屬性”。于是就變成了: ? Class MyClass { public: int GetState(); private: int m_iState; } int MyClass::GetState() { return m_iState; } ? ? 這樣一來(lái),面向?qū)ο笏枷氲故求w現(xiàn)出來(lái)了,但你的CPU會(huì)恨你:“你丫的,一個(gè)鳥樣小的函數(shù)就返回一個(gè)整數(shù)卻讓老子進(jìn)一次棧、彈一次棧”,內(nèi)存也會(huì)憋屈的說(shuō):“兄弟,老子也得跟著分配內(nèi)存啊!” ?
? ? 但對(duì)你來(lái)說(shuō),也很委屈,怎么辦,把所有的屬性都改成public?讓外部?jī)?nèi)碼直接訪問(wèn)?況且,那樣也不解決所有問(wèn)題,因?yàn)橛袝r(shí)候即使不是為了面向?qū)ο?#xff0c;我們也需要把獨(dú)立的功能模塊做成函數(shù),比如說(shuō)產(chǎn)生隨機(jī)數(shù)的函數(shù)。我想 ?
int iRand=rand(); ?
總比: ?
int iRand=((int)(MULTIPLIER * Seed + INCREMENT)>>16)&0x7fff; ?
? ? 看起來(lái)舒服吧?(我這里只是打個(gè)比方,VC的rand函數(shù)并不是內(nèi)聯(lián)函數(shù)) ?
? ? 而內(nèi)聯(lián)函數(shù)就是解決這個(gè)問(wèn)題了,對(duì)于程序員,他還是把獨(dú)立功能寫成函數(shù)的形式,但只要聲明為內(nèi)聯(lián),編譯器就不把它編譯成一次函數(shù)調(diào)用,而只是類似于把函數(shù)的代碼拷貝到被調(diào)用的地方,而且這完全是編譯器私下里完成的,原來(lái)的訪問(wèn)權(quán)限等問(wèn)題絲毫不受影響。這不是兩全齊美了嗎:在保證代碼的面向?qū)ο笮院徒Y(jié)構(gòu)化不受損失的條件下,程序的效率也沒(méi)有損失,比如上面那個(gè)類,就變成了: ?
Class MyClass { public: inline int GetState(); private: int m_iState; } int inline MyClass::GetState() { return m_iState; } ? ? 有一點(diǎn)要注意,內(nèi)聯(lián)函數(shù)要跟類的聲明寫在同一個(gè)文件中,否則編譯會(huì)出錯(cuò)。按照VC管理源文件的風(fēng)格來(lái)說(shuō),就是內(nèi)聯(lián)函數(shù)最好寫在聲明類的.h文件中,而不是像一般函數(shù)那樣寫在實(shí)現(xiàn)類的.cpp文件中。 ?
? ? 當(dāng)然,內(nèi)聯(lián)函數(shù)還有另外一種寫法,就是直接寫在類中,此時(shí),不必使用“inline”關(guān)鍵字。 ?
Class MyClass { public: int GetState(){ return m_iState; } private: int m_iState; } ? ? 最后,還要注意,內(nèi)聯(lián)函數(shù)只是一種編譯機(jī)制,用上面兩種形式聲明的函數(shù)僅僅是建議編譯器進(jìn)行內(nèi)聯(lián),而編譯器是否內(nèi)聯(lián)不一定。正如前面所說(shuō),函數(shù)調(diào)用的開銷只是對(duì)小的函數(shù)不可忽略,對(duì)于重量級(jí)的函數(shù)還是可以忽略的,而且在絕大多數(shù)的場(chǎng)合,函數(shù)調(diào)用才是人間正道,才是解決問(wèn)題的最佳。所以大多數(shù)編譯器并不把帶有循環(huán)、遞歸等或者代碼比較多的函數(shù)進(jìn)行內(nèi)聯(lián)編譯,有的甚至不允許聲明成內(nèi)聯(lián)的。 ? ?
? ? 在解決C + +中宏存取私有的類成員的問(wèn)題過(guò)程中,所有和預(yù)處理器宏有關(guān)的問(wèn)題也隨著消失了。這是通過(guò)使宏被編譯器控制來(lái)實(shí)現(xiàn)的。在 C + +中,宏的概念是作為內(nèi)聯(lián)函數(shù)來(lái)實(shí)現(xiàn)的,而內(nèi)聯(lián)函數(shù)無(wú)論在任何意義上都是真正的函數(shù)。唯一不同之處是內(nèi)聯(lián)函數(shù)在適當(dāng)時(shí)像宏一樣展開,所以函數(shù)調(diào)用的開銷被取消。因此,應(yīng)該永遠(yuǎn)不使用宏,只使用內(nèi)聯(lián)函數(shù)。 ?
? ? 任何在類中定義的函數(shù)自動(dòng)地成為內(nèi)聯(lián)函數(shù),但也可以使用i n l i n e關(guān)鍵字放在類外定義的函數(shù)前面使之成為內(nèi)聯(lián)函數(shù)。但為了使之有效,必須使函數(shù)體和聲明結(jié)合在一起,否則,編譯器將它作為普通函數(shù)對(duì)待。因此 ?
inline int PlusOne(int x); ? ? 沒(méi)有任何效果,僅僅只是聲明函數(shù)(這不一定能夠在稍后某個(gè)時(shí)候得到一個(gè)內(nèi)聯(lián)定義)。成功的方法如下: ?
inline int PlusOne(int x) { return ++x ;} ? ? 注意,編譯器將檢查函數(shù)參數(shù)列表使用是否正確,并返回值(進(jìn)行必要的轉(zhuǎn)換)。這些事情是預(yù)處理器無(wú)法完成的。假如對(duì)于上面的內(nèi)聯(lián)函數(shù),我們寫成一個(gè)預(yù)處理器宏的話,將有不想要的副作用。 ?
? ? 一般應(yīng)該把內(nèi)聯(lián)定義放在頭文件里。當(dāng)編譯器看到這個(gè)定義時(shí),它把函數(shù)類型(函數(shù)名+ ?返回值)和函數(shù)體放到符號(hào)表里。當(dāng)使用函數(shù)時(shí),編譯器檢查以確保調(diào)用是正確的且返回值被 ?正確使用,然后將函數(shù)調(diào)用替換為函數(shù)體,因而消除了開銷。內(nèi)聯(lián)代碼的確占用空間,但假如函數(shù)較小,這實(shí)際上比為了一個(gè)普通函數(shù)調(diào)用而產(chǎn)生的代碼(參數(shù)壓棧和執(zhí)行C A L L)占用的空間還少。在頭文件里,內(nèi)聯(lián)函數(shù)默認(rèn)為內(nèi)部連接——即它是static, 并且只能在它被包含的編譯單元看到。因而,只要它們不在相同的編譯單元中聲明,在內(nèi)聯(lián)函數(shù)和全局函數(shù)之間用同樣的名字也不會(huì)在連接時(shí)產(chǎn)生沖突。 ?
? ? 為了定義內(nèi)聯(lián)函數(shù),通常必須在函數(shù)定義前面放一個(gè)i n l i n e關(guān)鍵字。但這在類內(nèi)部定義內(nèi)聯(lián)函數(shù)時(shí)并不是必須的。任何在類內(nèi)部定義的函數(shù)自動(dòng)地為內(nèi)聯(lián)函數(shù)。如下例: ?
#include <iostream.h> class point{ private: int i,j,k; public: point() {i=j=k=0; } point(int I,int J,int K) { i=I; j=J k=K; } void print(const char* msg="") const{ if(*msg) cout<<"msg"<<endl; cout<<"i="<<i<<endl; cout<<"j="<<j<<endl; cout<<"k="<<k<<endl; } }; main(){ point p,q(1,2,3); p.print("value of p"); q.print("value of q"); } ? ? 當(dāng)然,因?yàn)轭悆?nèi)部的內(nèi)聯(lián)函數(shù)節(jié)省了在外部定義成員函數(shù)的額外步驟,所以我們一定想在類聲明內(nèi)每一處都使用內(nèi)聯(lián)函數(shù)。但應(yīng)記住,內(nèi)聯(lián)的目的是減少函數(shù)調(diào)用的開銷。假如函數(shù)較大,那么花費(fèi)在函數(shù)體內(nèi)的時(shí)間相對(duì)于進(jìn)出函數(shù)的時(shí)間的比例就會(huì)較大,所以收獲會(huì)較小。而且內(nèi)聯(lián)一個(gè)大函數(shù)將會(huì)使該函數(shù)所有被調(diào)用的地方都做代碼復(fù)制,結(jié)果代碼膨脹而在速度方面獲得的好處卻很少或者沒(méi)有。

總結(jié)

以上是生活随笔為你收集整理的inline内联的用法与作用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。