C 語言 宏定義和宏函數

 

 

在軟件開發過程中,經常有一些常用或者通用的功能或者代碼段,這些功能既可以寫成函數,也可以封裝成爲宏定義。那麼究竟是用函數好,還是宏定義好?這就要求我們對二者進行合理的取捨。

我們來看一個例子,比較兩個數或者表達式大小,首先我們把它寫成宏定義:

#define MAX( a, b) ( (a) > (b)?(a) : (b) )

其次,把它用函數來實現:

 int max( int a, int b)

 {
  return (a > b a : b)
 }

很顯然,我們不會選擇用函數來完成這個任務,

原因有兩個:首先,函數調用會帶來額外的開銷,它需要開闢一片棧空間,記錄返回地址,將形參壓棧,從函數返回還要釋放堆棧。這種開銷不僅會降低代碼效率,而且代碼量也會大大增加,而使用宏定義則在代碼規模和速度方面都比函數更勝一籌;其次,函數的參數必須被聲明爲一種特定的類型,所以它只能在類型合適的表達式上使用,我們如果要比較兩個浮點型的大小,就不得不再寫一個專門針對浮點型的比較函數。反之,上面的那個宏定義可以用於整形、長整形、單浮點型、雙浮點型以及其他任何可以用“>”操作符比較值大小的類型,也就是說,宏是與類型無關的

  和使用函數相比,使用宏的不利之處在於每次使用宏時,一份宏定義代碼的拷貝都會插入到程序中。除非宏非常短,否則使用宏會大幅度增加程序的長度。

還有一些任務根本無法用函數實現,但是用宏定義卻很好實現。比如參數類型沒法作爲參數傳遞給函數,但是可以把參數類型傳遞給帶參的宏。

  看下面的例子:

#define MALLOC(n, type) \

  ( (type *) malloc((n)* sizeof(type)))

利用這個宏,我們就可以爲任何類型分配一段我們指定的空間大小,並返回指向這段空間的指針。我們可以觀察一下這個宏確切的工作過程:

int *ptr;

  ptr = MALLOC ( 5, int );

  將這宏展開以後的結果:

  ptr = (int *) malloc ( (5) * sizeof(int) );

 

屬性

#define宏

函數

代碼長度

每次使用時,宏代碼都被插入到程序中。除了非常小的宏之外,程序的長度將大幅度增長

函數代碼只出現於一個地方:每次使用這個函數時,都調用那個地方的同一份代碼

執行速度

更快

存在函數調用、返回的額外開銷

操作符優先級

宏參數的求值是在所有周圍表達式的上下文環境裏,除非它們加上括號,否則鄰近操作符的優先級可能產生不可預料的結果。

函數參數只在函數調用時求值一次,它的結果值傳遞給函數。表達式的求值結果更容易預測。

參數求值

參數用於宏定義時,每次都將重新求值,由於多次求值,具有副作用的參數可能會產生不可預測的結果。

參數在函數調用前只求值一次,在函數中多次使用參數並不會導致多次求值過程,參數的副作用並不會造成任何特殊問題。

參數類型

宏與類型無關,只要參數的操作是合法的,它可以用於任何參數類型。

函數的參數是與類型有關係的,如果參數的類型不同,就需要使用不同的函數,即使它們執行的任務是相同的。

define的多行定義

#define   MACRO(arg1,   arg2)   do   {   \
   \
stmt1;   \
stmt2;   \
   \
}   while(0)  
關鍵是要在每一個換行的時候加上一個 "\ "

宏定義必須寫在函數之外,其作用域爲宏定義命令起到源程序結束。如要終止其作用域可使用#undef命令。

 

 

一個小栗子:

#include<iostream>
#include<cstring>
using namespace std;
#define swap(a,b)  \
    a^=b;\
    b^=a;\
    a^=b;
#define Max(a,b) ((a)>(b)?(a):(b))
int main(){
	string s;
	int n,m;
	cin>>n>>m;
	swap(n,m);
	cout<<n<<m<<endl;
	cout<<Max(n,m)<<endl;
	return 0;
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章