C++ 函數 內聯函數


內聯函數的功能和預處理宏的功能相似,在介紹內聯函數之前,先介紹一下預處理宏。宏是簡單字符替換,最常見的用法:定義了一個代表某個值的全局符號、定義可調用帶參數的宏。作為一種約定,習慣上總是用大寫字母來定義宏,宏還可以替代字符常量。我們會經常定義一些宏,如:

#define ADD(a,b) a+b

那為什么需要使用宏呢?因為調用函數需要一定的時間和空間開銷。

執行到函數調用指令時,程序將在函數調用后立即存儲該指令的內存地址,並將函數參數復制到堆棧(為此保留的內存塊),跳到標記函數起點的內存單元,執行函數代碼(也許還需將返回值放入寄存器中),然后跳回到地址被保存的指令處(這與閱讀文章時停下來看腳注,並在閱讀完腳注后返回到以前閱讀的地方類似)。來回跳躍並記錄跳躍位置意味着以前使用函數時,需要一定的開銷。

而宏僅僅是在預處理的地方把代碼展開,不需要額外的時間空間方面的開銷。

宏也有很多的不盡人意的地方,所以c++中用內聯函數來代替宏。
(1)宏不能訪問對象的私有成員。類的私有成員只能通過類的成員函數或友元函數來訪問,
(2)宏不進行類型檢查。例如上面定義的ADD宏,要注意傳入實參的類型,如果你傳入的參數不是char, int, float, double,而是其他類型,可能就會出錯。
(3)宏的定義很容易產生二義性。

 

#define MULTI(x) (x*x) 

我們用一個數字去調用它,MULTI(10),這樣看上去沒有什么錯誤,結果返回100,是正確的;但是如果我們用MULTI(10+10)去調用的話,我們期望的結果是400,而宏的調用結果是(10+10*10+10),結果是120,這顯然不是我們要得到的結果。為避免這種錯誤,可給宏的參數都加上括號。
      

 

 #define MULTI(x) ((x)*(x)) 

這樣可以確保MULTI(10+10)不會出錯,但是若使用MULTI(a++)調用它,他們本意是希望得到(a+1)*(a+1)的結果,但是宏的展開結果是:(a++)*(a++),如果a的值是2,我們得到的結果是2*3=6。而我們期望的結果是3*3=9。

內聯函數的方法很簡單,只需在函數首行的左端加一個關鍵字inline即可 。
在編譯時將所調用函數的代碼直接嵌入到主調函數中,而不是將流程轉出去,這種嵌入到主調函數中的函數成為內聯函數。

 

#include <iostream>
using namespace std;
inline int max(int,int, int);       //聲明函數,注意左端有inline
int main( )
{
    int i=10,j=20,k=30,m;
    m=max(i,j,k);
    cout<<″max=″<<m<<endl;
    return 0;
}
inline int max(int a,int b,int c)    //定義max為內置函數
{
    if(b>a) a=b;          //求a,b,c中的最大者
    if(c>a) a=c;
    return a;
}

 

由於在定義函數時指定它為內置函數,因此編譯系統在遇到函數調用“max(i,j,k)”時,就用max函數體的代碼代替“max(i,j,k)”,同時將實參代替形參。
這樣,程序代碼“m=max(i,j,k);”就被置換成:
      

 if (j>i) i=j;
 if (k>i) i=k;
        m=i;

 

內聯函數必須是和函數體在一起,才有效。如下風格的函數不能成為內聯函數:

inline void Fun(int x, int y);  // inline僅與函數聲明放在一起
void Fun (int x, int y) {…} 


而如下風格的函數Fun則成為內聯函數:

void Fun(int x, int y);
inline void Fun(int x, int y) {…} // inline與函數定義體放在一起 

因此,inline是一種“用於實現的關鍵字”,而不是一種“用於聲明的關鍵字”。

內聯函數和宏的區別在於,宏是由預處理器對宏進行替代,而內聯函數是通過編譯器控制來實現的。而且內聯函數是真正的函數,只是在需要用到的時候,內聯函數像宏一樣的展開,所以取消了函數的參數壓棧,減少了調用的開銷。你可以象調用函數一樣來調用內聯函數,而不必擔心會產生於處理宏的一些問題。內聯函數與帶參數的宏定義進行下比較,它們的代碼效率是一樣,但是內聯歡函數要優於宏定義,因為內聯函數遵循的類型和作用域規則,它與一般函數更相近,在一些編譯器中,一旦關聯上內聯擴展,將與一般函數一樣進行調用,比較方便。 

       另外,宏定義在使用時只是簡單的文本替換,並沒有做嚴格的參數檢查,也就不能享受C++編譯器嚴格類型檢查的好處,另外它的返回值也不能被強制轉換為可轉換的合適的類型,這樣,它的使用就存在着一系列的隱患和局限性。C++的inline的提出就是為了完全取代宏定義,因為inline函數取消了宏定義的缺點,又很好地繼承了宏定義的優點

 

內聯函數是以代碼膨脹(復制)為代價,這省去了函數調用的開銷,從而提高函數的執行效率。另一方面,每一處內聯函數的調用都要復制代碼,將使程序的總代碼量增大,消耗更多的內存空間。以下情況不宜使用內聯:
(1)如果函數體內的代碼比較長,使用內聯將導致內存消耗代價較高。
(2)內聯函數中不能包括復雜的控制語句,如循環語句和switch語句。如果函數體內出現循環,那么執行函數體內代碼的時間要比函數調用的開銷大。

同時要注意inline關鍵字只是表示一個請求,編譯器並不會一定將inline修飾的函數作為內聯,有的沒有被inline修飾的函數在一些編譯器中也可能被編譯為內聯。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM