/*宏定義的方式*/ #define MAX(x,y) (((x)>(y)) ? (x):(y)) #define MIN(x,y) (((x)<(y)) ? (x):(y)) /*函數的方式*/ int max(int x,int y) { return (x>y?x:y); } int min(int x,int y) { return (x<y?x:y); }從表面上來看這兩個範例,使用宏的封裝方式明顯優於函數的方式,原因很簡單:如果這裡要繼續比較兩個浮點型別數的大小時,就不得不再寫兩個專門針對浮點型別數的比較函數,對於其他型別數的比較以此類推;而宏定義因為不存在任何型別問題,因此可以用於整型、長整型、浮點型以及其他任何可以使用“>”與“<”操作符比較值大小的型別,正所謂一勞永逸。
int i1=0; int i2=1; int i3=2; int i4=3; int i5=4; int max=MAX(i1,(MAX(i2,(MAX(i3,MAX(i4,i5))))));接下來,編譯器對語句“MAX(i1,(MAX(i2,(MAX(i3,MAX(i4,i5))))))”進行展開如下:
(((i1)>(((((i2)>(((((i3)>((((i4)>(i5)) ? (i4) : (i5)))) ? (i3) : ((((i4)>(i5)) ? (i4) : (i5))))))) ? (i2) : (((((i3)>((((i4)>(i5)) ? (i4) : (i5)))) ? (i3) : ((((i4)>(i5)) ? (i4) : (i5)))))))))) ? (i1) : (((((i2)>(((((i3)>((((i4)>(i5)) ? (i4) : (i5)))) ? (i3) : ((((i4)>(i5)) ? (i4) : (i5))))))) ? (i2) : (((((i3)>((((i4)>(i5)) ? (i4) : (i5)))) ? (i3) : ((((i4)>(i5)) ? (i4) : (i5))))))))));
上面的展開程式碼看起來很鬱悶,基本快花眼了。當然,這裡還可以對宏呼叫語句進行優化,如下面的範例程式碼所示:MAX(MAX(MAX(i1,i2),MAX(i3,i4)),i5);現在看起來雖然精簡許多,但還不是很樂觀,展開程式碼如下所示:
(((((((((i1)>(i2)) ? (i1) : (i2)))>((((i3)>(i4)) ? (i3) : (i4)))) ? ((((i1)>(i2)) ? (i1) : (i2))) : ((((i3)>(i4)) ? (i3) : (i4)))))>(i5)) ? (((((((i1)>(i2)) ? (i1) : (i2)))>((((i3)>(i4)) ? (i3) : (i4)))) ? ((((i1)>(i2)) ? (i1) : (i2))) : ((((i3)>(i4)) ? (i3) : (i4))))) : (i5));
面對這種情況,有讀者或許會認為函數比宏方便,程式碼也顯得苗條與可愛多了。但不能夠一概而論,應具體情況具體分析。#define MALLOC(n,type) ((type *) malloc((n)* sizeof(type)))現在,利用 MALLOC 宏,就可以為任何型別分配一段指定的空間大小,並返回指向這段空間的指標。如下面的範例程式碼所示:
p = MALLOC(8,int);展開以後的結果為:
p = (int *) malloc((8) * sizeof(int));由此可見,宏定義有時候還可以完成函數不能夠完成的一些特殊功能。因此,如何取捨這二者,還需要根據具體情況具體分析,千萬不能夠武斷地做出判斷。一般來說,應該用宏去替換小的、可重複的程式碼段,這樣可以使程式執行速度更快。當任務比較複雜,需要多行程式碼才能實現時,或者要求程式越小越好時,就應該使用函數。