??? 內聯函數
??? 目錄
??????? 定義
??????? 動機
??????? 函數內聯問題
??????? 行情
??????? 宏比較
??????? 注意事項
??? 編輯本段定義
??? 內聯函數從源代碼層看,有函數的結構,而在編譯后,卻不具備函數的性質。編譯時,類似宏替換,使用函數體替換調用處的函數名。一般在代碼中用inline修飾,但是能否形成內聯函數,需要看編譯器對該函數定義的具體處理。
??? 編輯本段動機
??? 內聯擴展是用來消除函數調用時的時間開銷。它通常用于頻繁執行的函數。 一個小內存空間的函數非常受益。
??? 如果沒有內聯函數,編譯器可以決定哪些函數內聯 。 程序員很少或沒有控制哪些職能是內聯的,哪些不是。 給這種控制程度,作用是程序員可以選擇內聯的特定應用 。
??? 編輯本段函數內聯問題
??? 除了 相關的問題, 內聯擴展一般,語言功能作為一個內聯函數可能不被視為有價值的,因為它們出現的原因,對于一個數字:
??? 通常,一個編譯器是在一個比人類更有利的地位來決定某一特定功能是否應該被內聯。 有時,編譯器可能無法盡可能多的功能內嵌作為程序員表示。
??? 一個重要的一點需要注意的是代碼(內聯函數)得到暴露其客戶端(調用函數)。
??? 隨著功能的演變,它們有可能成為合適的內聯,他們不前,或不再在他們面前的內聯合適。 而內聯或取消內聯函數比從宏轉換為更容易,但仍需要額外的維修,一般產量相對較少的利益。
??? 用于本機C型編譯系統的擴散可以增加編譯時間,因為他們的身體的中間表示是到每個調用點,他們都是內聯復制內聯函數。在代碼大小可能增加是由在編譯時間可能增加鏡像。
??? C99中內嵌的規范要求只有一個額外在另一個編譯單元,功能的外部定義時,相應的內聯定義,可以發生在不同的編譯單元多次,如果該函數用于地方。這很容易導致連接器,因為這樣的定義不是由程序員提供的錯誤。 出于這個原因,往往是在C99內聯一起使用靜態的,也給出了函數的內部聯系。
??? 在C + +,有必要定義一個在每一個模塊(編譯單元)內聯函數使用一個普通的功能,而必須在只有一個模塊中定義它。否則,就不可能編制的所有其他模塊一個模塊獨立。
??? 對于功能問題與優化本身,而不是語言,請參閱使用內聯擴展問題 。
??? 內聯函數是使用inline關鍵字聲明的函數,也成內嵌函數,它主要的作用是解決程序的運行效率。
??? 使用內聯函數的時候要注意:
??? 1.遞歸函數不能定義為內聯函數
??? 2.內聯函數一般適合于不存在while和switch等復雜的結構且只有1~5條語句的小函數上,否則編譯系統將該函數視為普通函數。
??? 3.內斂函數只能先定義后使用,否則編譯系統也會把它認為是普通函數。
??? 4.對內斂函數不能進行異常的接口聲明。
??? 編輯本段行情
??? “一個函數聲明[。。。]說明符聲明一個內聯與內聯函數。內聯說明符指示的實現,內聯函數體替代了在調用點是首選通常的函數調用機制。一個實現不要求在調用執行此點內聯替代,但是,即使這個內嵌替代省略,由7.1.2內聯函數定義的其他規則,仍應得到尊重“。
??? - 國際標準化組織14882:1998(E)的,目前的C + +標準,第7.1.2
??? “的函數說明符聲明的內聯函數是一個內聯函數。[。。。]制作一個內聯函數的函數表明該函數被調用盡可能快。在何種程度上這些建議是有效的,是實現定義( 注:例如,一個實施內聯替換可能不會執行,或者可能只執行替換內聯在聲明中要求的范圍內聯的)。
??? “[。。。]內聯定義不提供外部定義的功能,并且不禁止的定義,還有一個是外部的翻譯單位。一個內聯定義提供了任何其他的外部定義,翻譯可能用來實現呼吁在相同的翻譯單元的功能。沒有指定是否調用該函數內聯定義或使用外部定義。”
??? - 國際標準化組織9899:1999(E)的C99標準,第6.7.4
??? 編輯本段宏比較
??? 內聯函數的功能和預處理宏的功能相似。相信大家都用過預處理宏,我們會經常定義一些宏,如
??? #define TABLE_COMP(x) ((x)>0?(x):0)
??? 就定義了一個宏。
??? 為什么要使用宏呢?因為函數的調用必須要將程序執行的順序轉移到函數
??? 所存放在內存中的某個地址,將函數的程序內容執行完后,再返回到轉去執行
??? 該函數前的地方。這種轉移操作要求在轉去執行前要保存現場并記憶執行的地
??? 址,轉回后要恢復現場,并按原來保存地址繼續執行。因此,函數調用要有一
??? 定的時間和空間方面的開銷,于是將影響其效率。而宏只是在預處理的地方把
??? 代碼展開,不需要額外的空間和時間方面的開銷,所以調用一個宏比調用一個
??? 函數更有效率。
??? 但是宏也有很多的不盡人意的地方。
??? 1、.宏不能訪問對象的私有成員。
??? 2、.宏的定義很容易產生二義性。
??? 我們舉個例子:
??? #define TABLE_MULTI(x) (x*x)
??? 我們用一個數字去調用它,TABLE_MULTI(10),這樣看上去沒有什么錯誤,
??? 結果返回100,是正確的,但是如果我們用TABLE_MULTI(10+10)去調用的話,
??? 我們期望的結果是400,而宏的調用結果是(10+10*10+10),結果是120,這顯
??? 然不是我們要得到的結果。避免這些錯誤的方法,一是給宏的參數都加上括號。
??? #define TABLE_MULTI(x) ((x)*(x))
??? 這樣可以確保不會出錯,但是,即使使用了這種定義,這個宏依然有可能
??? 出錯,例如使用TABLE_MULTI(a++)調用它,他們本意是希望得到(a+1)*(a+1)的
??? 結果,而實際上呢?我們可以看看宏的展開結果: (a++)*(a++),如果a的值是
??? 4,我們得到的結果是4*4 = 16,a = 6。而我們期望的結果是5*5=25,這又出現了問題。
??? 事實上,在一些C的庫函數中也有這些問題。例如:Toupper(*pChar++)就會對
??? pChar執行兩次++操作,因為Toupper實際上也是一個宏。
??? 我們可以看到宏有一些難以避免的問題,怎么解決呢?
??? 下面就是用我要介紹的內聯函數來解決這些問題,我們可以使用內聯函數
??? 來取代宏的定義。而且事實上我們可以用內聯函數完全取代預處理宏。
??? 內聯函數和宏的區別在于,宏是由預處理器對宏進行替代,而內聯函數是
??? 通過編譯器控制來實現的。而且內聯函數是真正的函數,只是在需要用到的時
??? 候,內聯函數像宏一樣的展開,所以取消了函數的參數壓棧,減少了調用的開
??? 銷。你可以象調用函數一樣來調用內聯函數,而不必擔心會產生于處理宏的一
??? 些問題。
??? 我們可以用Inline來定義內聯函數,不過,任何在類的說明部分定義的函
??? 數都會被自動的認為是內聯函數。
??? 下面我們來介紹一下內聯函數的用法。
??? 內聯函數必須是和函數體申明在一起,才有效。像這樣的申明
??? Inline Tablefunction(int I)是沒有效果的,編譯器只是把函數作為普通的函
??? 數申明,我們必須定義函數體。
??? Inline tablefunction(int I) {return I*I};
??? 這樣我們才算定義了一個內聯函數。我們可以把它作為一般的函數一樣調
??? 用。但是執行速度確比一般函數的執行速度要快。
??? 我們也可以將定義在類的外部的函數定義為內聯函數,比如:
??? Class TableClass{
??? Private:
??? Int I,j;
??? Public:
??? Int add() { return I+j;}
??? Inline int dec() { return I-j;}
??? Int GetNum();
??? }
??? inline int tableclass::GetNum(){
??? return I;
??? }
??? 上面申明的三個函數都是內聯函數。在C++中,在類的內部定義了函數體的
??? 函數,被默認為是內聯函數。而不管你是否有inline關鍵字。
??? 內聯函數在C++類中,應用最廣的,應該是用來定義存取函數。我們定義的
??? 類中一般會把數據成員定義成私有的或者保護的,這樣,外界就不能直接讀寫我
??? 們類成員的數據了。
??? 對于私有或者保護成員的讀寫就必須使用成員接口函數來進行。如果我們把
??? 這些讀寫成員函數定義成內聯函數的話,將會獲得比較好的效率。
??? Class sample{
??? Private:
??? Int nTest;
??? Public:
??? Int readtest(){ return nTest;}
??? Void settest(int I) {nTest=I;}
??? }
??? 當然,內聯函數也有一定的局限性。就是函數中的執行代碼不能太多了,如
??? 果,內聯函數的函數體過大,一般的編譯器會放棄內聯方式,而采用普通的方式
??? 調用函數。這樣,內聯函數就和普通函數執行效率一樣了。
??? 編輯本段注意事項
??? 使用內聯函數應注意的事項
??? 內聯函數具有一般函數的特性,它與一般函數所不同之處只在于函數調用的處理。一般函數進行調用時,要將程序執行權轉到被調用函數中,然后再返回到調用它的函數中;而內聯函數在調用時,是將調用表達式用內聯函數體來替換。在使用內聯函數時,應注意如下幾點: 1.在內聯函數內不允許用循環語句和開關語句。 如果內聯函數有這些語句,則編譯將該函數視同普通函數那樣產生函數調用代碼,遞歸函數(自己調用自己的函數)是不能被用來做內聯函數的。內聯函數只適合于只有1~5行的小函數。對一個含有許多語句的大函數,函數調用和返回的開銷相對來說微不足道,所以也沒有必要用內聯函數實現。 2.內聯函數的定義必須出現在內聯函數第一次被調用之前。 3.本欄目講到的類結構中所有在類說明內部定義的函數是內聯函數。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
