程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 內聯函數和宏定義的區別

內聯函數和宏定義的區別

編輯:關於C語言
 

用內聯取代宏:

1.內聯函數在運行時可調試,而宏定義不可以;
2.編譯器會對內聯函數的參數類型做安全檢查或自動類型轉換(同普通函數),而宏定義則不會;
3.內聯函數可以訪問類的成員變量,宏定義則不能;
4.在類中聲明同時定義的成員函數,自動轉化為內聯函數。

文章(一)

內聯函數與宏定義
  在C中,常用預處理語句#define來代替一個函數定義。例如:
    #define MAX(a,b) ((a)>(b)?(a):(b))
  該語句使得程序中每個出現MAX(a,b)函數調用的地方都被宏定義中後面的表達式((a)>(b)?(a):(b))所替換。

  宏定義語句的書寫格式有過分的講究, MAX與括號之間不能有空格,所有的參數都要
  放在括號裡。盡管如此,它還是有麻煩:
    int a=1,b=0;
    MAX(a++,b); //a被增值2次
    MAX(a++,b+10); //a被增值1次
    MAX(a,"Hello"); //錯誤地比較int和字符串,沒有參數類型檢查
    MAX( )函數的求值會由於兩個參數值的大小不同而產生不同的副作用。
    MAX(a++,b)的值為2,同時a的值為3;
    MAX(a++,b+10)的值為10,同時a的值為2。
  如果是普通函數,則MAX(a,"HellO")會受到函數調用的檢查,但此處不會因為兩個參數類型不同而被編譯拒之門外。幸運的是,通過一個內聯函數可以得到所有宏的替換效能和 所有可預見的狀態以及常規函數的類型檢查:
    inline int MAX(int a,int b)
    {
     return a>b?a:b;
    }

1.內聯函數與宏的區別:

傳統的宏定義函數可能會引起一些麻煩。

ex:

#define F(x) x+x

void main(){int i=1;F(i++);}

這裡x將被加兩次。

內聯函數被編譯器自動的用函數的形勢添加進代碼,而不會出現這種情況。

內聯函數的使用提高了效率(省去了很多函數調用匯編代碼如:call和ret等)。

2.內聯函數的使用:

所有在類的聲明中定義的函數將被自動認為是內聯函數。

class A()

{

void c();// not a inline function;

void d(){ print("d() is a inline function.");}

}

如果想將一個全局函數定義為內聯函數可用,inline 關鍵字。

inline a(){print("a() is a inline function.");}

注意:

在內聯函數中如果有復雜操作將不被內聯。如:循環和遞歸調用。

總結:

將簡單短小的函數定義為內聯函數將會提高效率。

文章(二)

8.5.1 用內聯取代宏代碼
C++ 語言支持函數內聯,其目的是為了提高函數的執行效率(速度)。
在 C程序中,可以用宏代碼提高執行效率。宏代碼本身不是函數,但使用起來象函數。預處理器用復制宏代碼的方式代替函數調用,省去了參數壓棧、生成匯編語言的 CALL調用、返回參數、執行return等過程,從而提高了速度。使用宏代碼最大的缺點是容易出錯,預處理器在復制宏代碼時常常產生意想不到的邊際效應。例如
#define MAX(a, b) (a) > (b) ? (a) : (b)
語句
result = MAX(i, j) + 2 ;
將被預處理器解釋為
result = (i) > (j) ? (i) : (j) + 2 ;
由於運算符‘+’比運算符‘:’的優先級高,所以上述語句並不等價於期望的
result = ( (i) > (j) ? (i) : (j) ) + 2 ;
如果把宏代碼改寫為
#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
則可以解決由優先級引起的錯誤。但是即使使用修改後的宏代碼也不是萬無一失的,例如語句
result = MAX(i++, j);
將被預處理器解釋為
result = (i++) > (j) ? (i++) : (j);
對於C++ 而言,使用宏代碼還有另一種缺點:無法操作類的私有數據成員。

讓我們看看C++ 的“函數內聯”是如何工作的。對於任何內聯函數,編譯器在符號表裡放入函數的聲明(包括名字、參數類型、返回值類型)。如果編譯器沒有發現內聯函數存在錯誤,那麼該函數的代碼也被放入符號表裡。在調用一個內聯函數時,編譯器首先檢查調用是否正確(進行類型安全檢查,或者進行自動類型轉換,當然對所有的函數都一樣)。如果正確,內聯函數的代碼就會直接替換函數調用,於是省去了函數調用的開銷。這個過程與預處理有顯著的不同,因為預處理器不能進行類型安全檢查,或者進行自動類型轉換。假如內聯函數是成員函數,對象的地址(this)會被放在合適的地方,這也是預處理器辦不到的。
C++ 語言的函數內聯機制既具備宏代碼的效率,又增加了安全性,而且可以自由操作類的數據成員。所以在C++ 程序中,應該用內聯函數取代所有宏代碼,“斷言assert”恐怕是唯一的例外。assert是僅在Debug版本起作用的宏,它用於檢查“不應該”發生的情況。為了不在程序的Debug版本和Release版本引起差別,assert不應該產生任何副作用。如果assert是函數,由於函數調用會引起內存、代碼的變動,那麼將導致Debug版本與Release版本存在差異。所以assert不是函數,而是宏。(參見6.5節“使用斷言”)  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved