1. 不能忽視宏定義中的空格
#define f (x) ((x)-1)
上面的宏定義中展開后變成
(x) ((x)-1)
而不是
((x)-1)
因為在f
和后面的(x)
之間多了一個空格赂毯!所以如果希望定義f(x)
為((x)-1)
焰盗,必須要這樣寫:
#define f(x) ((x)-1)
但調(diào)用宏的時候卻可以有空格可很,即在上面完成宏定義后钠署,f(3)
和f (3)
求值后都等于2.
2. 宏并不是函數(shù)
#define MAX(a,b) ((a)>(b)?(a):(b))
int max(int a, int b)
{
return (a>b?a:b);
}
在宏定義中允青,當一個操作數(shù)被兩處用到時萌衬,就會被求值2次姜盈,但是函數(shù)不會径缅!
int MAX_Val = 0,max_Val = 0;
int a=3,b=2;
MAX_Val = MAX(++a,b);
max_Val = max(++a,b);
運行結(jié)果MAX_Val
和max_Val
是不相等的中符,原因是因為宏展開時變成:
((++a)>(b)?(++a):(b))
在這里++a
運算了兩次姜胖!
以前經(jīng)常聽到別人說用宏定義代替函數(shù)是“用空間換時間”,原因是在C語言中調(diào)用函數(shù)時造成的系統(tǒng)開銷要大大多于函數(shù)體內(nèi)的實際計算操作淀散,所以用宏定義免去了調(diào)用函數(shù)的開銷右莱,自然時間就省了出來。但是宏展開可能產(chǎn)生非常龐大的表達式档插,占用的空間遠遠超過了編程者所期望的空間慢蜓。例如:
#define max((a)>(b)?(a):(b))
假如用上面定義的宏max
,來找到a,b,c,d
四個數(shù)的最大者郭膛,首先想到的寫法是:
max(a,max(b,max(c,d)))
展開后就是:
((a)>(((b)>(((c)>(d)?(c):(d)))?(b):(((c)>(d)?(c):(d)))))?(a):(((b)>(((c)>(d)?(c):(d)))?(b):(((c)>(d)?(c):(d))))))
這個式子太長了晨抡!如果調(diào)整下,寫成:
max(max(a,b),max(a,b))
展開后
((((a)>(b)?(a):(b)))>(((c)>(d)?(c):(d)))?(((a)>(b)?(a):(b))):(((c)>(d)?(c):(d))))
還是比較長则剃。
如果換成函數(shù)耘柱,更容易些!
int max(int a,int b,int c,int d)
{
int biggest = a;
if(biggest < b) biggest = b;
if(biggest < c) biggest = c;
if(biggest < d) biggest = d;
return biggest;
}
3. 宏并不是語句
#define assert(e) if(!(e)) assert_error(__FILE__,__LINE__)
宏assert
的這個定義棍现,即使用在一個再明白直接不過的情形中调煎,也會有一些難以察覺的錯誤。
if(x>0 && y>0)
assert(x>y);
else
assert(y>x);
展開后并做縮排處理:
if(x>0 && y>0)
if(!(x>y))
assert_error(__FILE__,__LINE__);
else
if(!(y>x))
assert_error(__FILE__,__LINE__);
這與我們所期望的流程結(jié)構(gòu)不一樣己肮!
如果在宏assert
的定義中用大括號把宏體整個給“括”起來士袄,那就沒有這樣的流程結(jié)構(gòu)錯誤。但是依然有問題產(chǎn)生:
#define assert(e) \
{if(!(e)) assert_error(__FILE__,__LINE__);}
繼續(xù)拿上面的例子谎僻,展開后變成
if(x>0 && y>0)
{if(!(x>y)) assert_error(__FILE__,__LINE__);};
else
{if(!(y>x)) assert_error(__FILE__,__LINE__);};
上面展開后在else
之前的分號是一個語法錯誤窖剑。要解決這個問題,一個辦法是對assert
的調(diào)用后面都不要再跟一個分號戈稿,另外一個辦法是:
#define assert(e) \
((void)((e)||assert_error(__FILE__,__LINE__)))