#define存在一些先天不足。在以下情形下要格外小心:
避免巨集引數中的++與--操作。
帶引數的巨集定義形式上與函式很接近,程式設計師呼叫時有時會把它們視為等價。但實際define定義的偽函式相比真正函式有一些使用限制,比如:
#define max(a,b)((a)>(b)?(a):(b)) //看上去是想得到兩個數中較大的
void main()
輸出結果: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 while(0) /* (no trailing ; ) */
這個定義有問題麼?是的,只是每行結尾的空格在**編輯器中一般看不到。一旦寫完換行符』\』後大拇指習慣性一按,乙個「**」錯誤就產生了。如果總提示多行define定義有錯,又找不到問題時,先把換行符\後的空格清理一下。
此外,define語句後不能隨便加;號:
#define min(a,b) ((a) <= (b) ? (a) : (b));
仔細看,行尾多了;號,#define不是c語句,不能隨便加;號,否則替換時;號也會跟著。
總結:
define僅僅是**替換,有時形似「函式定義」但不是真正的函式定義。另外define還會使除錯不方便,所以建議用const量和inline函式替換#define。
c陷阱與缺陷 陷阱
例1 if x y break 這就話的意思就是把y賦值x,判斷x是否為0,實則是在判斷y是否為0 例2 while c c t c n 這句話的意思就是 c t c n 賦值給c,而有 符本身就是不為0的數,所以這就是while 1 的意思。例3 int x 4,p new int p 2 cou...
C缺陷與陷阱 詞法陷阱
從較低的層面考察,程式是由符號 token 序列組成的,將程式分解成符號的過程,稱為詞法分析。這節主要分析在程式被詞法分析器分解成各個符號的過程中可能出現的問題。編譯器中負責將程式分解成乙個乙個符號的部分,一般稱之為詞法分析器。c語言中符號之間的空白 包括空格符,製表符和換行符 將被忽略。術語符號 ...
c陷阱與缺陷 語法「陷阱
語法 陷阱 語法是在詞法的基礎上延伸,它教怎樣組合成宣告,表示式,語句和程式 理解函式宣告 任何c變數宣告都是由 型別 一組類似表示式的宣告符 float f 乙個簡單的變數宣告 float f 這是乙個函式宣告,其返回值 float型別的函式 float f 這是乙個指向float型別的指標 fl...