#define存在一些先天不足。在以下情形下要格外小心:
避免宏參數中的++與--操作。
帶參數的宏定義形式上與函數很接近,程式員調用時有時會把它們視為等價。但實際define定義的僞函數相比真正函數有一些使用限制,比如:
#define max(A,B)((A)>(B)?(A):(B)) //看上去是想得到兩個數中較大的
void main()
{
int i=1, j=2, x;
x = max(i++, j++);
printf("x = %d\n", x);
printf("i = %d\n", i);
printf("j = %d\n", j);
}
輸出結果:x = 3 i = 2 j = 4。為什麼不是x = 2, i = 2, j = 3? 因為預處理器對宏做文本替換後變成:x = ((i++) > (j++) ? (i++) : (j++)),其中j将被計算兩次。是以用宏定義時,一定要小心操作數中的++ --,如果max是真正的函數,處理這種帶++ --的參數沒問題,但#define定義的僞函數卻不行。
C庫中的大小寫轉換函數toupper()也是一個典型例子,為減少函數調用開銷,很多C庫裡toupper用宏實作:#define toupper(c) ((c) >= 'a' && (c) <= 'z' ? (c) + ('A' - 'a') : (c))。它确實比函數調用快,但一旦遇到toupper(*p++)這種調用方式,也會出現奇怪結果。
宏定義的括号漏洞
#define add(A,B) A+B
x = add(1,2) * 10;
結果x=21。為什麼不是30?仔細看:add宏展開後表達式變成x = 1+2*10,定義裡沒用括号保護,展開後與預期功能不符,這種問題非常常見,再比如:
#define BLK_LEN 32 * 1024
block_num = bufsize / BLK_LEN;
替換後:block_num = stat_buf.st_size/32*1024;。是以宏定義裡要多用括号,避免幹擾。
不要用define代替typedef
#define pin (int*)
pin a,b;
本意a和b都定義為int指針,但替換後變成int* a,b;即a是int指針,而b是int變量。是以對這種類型重定義,應該用typedef,而不是不倫不類的define。
define多行定義續行符後不能有空格
define可定義多行代碼,但續行符後不能有空格,否則會産生很多編譯錯誤
#define MACRO(arg1, arg2) do { \
stmt1; \
\
} while(0)
這個定義有問題麼?是的,隻是每行結尾的空格在代碼編輯器中一般看不到。一旦寫完換行符’\’後大拇指習慣性一按,一個“隐形”錯誤就産生了。如果總提示多行define定義有錯,又找不到問題時,先把換行符\後的空格清理一下。
此外,define語句後不能随便加;号:
#define MIN(A,B) ((A) <= (B) ? (A) : (B));
仔細看,行尾多了;号,#define不是C語句,不能随便加;号,否則替換時;号也會跟着。
總結:
define僅僅是代碼替換,有時形似“函數定義”但不是真正的函數定義。另外define還會使調試不友善,是以建議用const量和inline函數替換#define。