#define 創建一個宏,該宏是標識符或參數化標識符與標記字符串的關聯。 在定義宏之後,編譯器可用標記字符串替換源文件中標識符的每個匹配項。
語法
#define identifier token-string
#define identifier ( identifier 1 , ... , identifier n ) token-string
備註
1 #define 指令促使編譯器用 token-string 替換源文件中 identifier 的每個匹配項。 僅當 identifier 構成標記時才替換它。 也就是說,如果 identifier 出現在註釋、字符串或較長的標識符中,則不會替換它。
2 第二種形式類似於函數,例如
#define mul(a,b) (a*b) 形參名稱將出現在 token-string 中以標記實際值的替換位置。
token-string 中前面未帶stringizing (#)、charizing(#@) 或 token-pasting (##) 運算符或後面未跟 ## 運算符的每個形參將由對應的實參替換。
注意:
1 宏就是簡單的字符替換,注意替換後的運算符優先級可能會影響宏定義所要表達的。所以要善於使用小括號。例如:
#define Add(a,b) a+b 如果使用的時候:2*Add(1,2) 原本想讓它等於6,但替換後變成2*1+2=4。所以要注意。
2 #define中的換行符是反斜槓\。如果一行沒寫完,直接加一個\,下一行繼續寫就可以了。
3 注意這裏只是字符替換,宏定義中不應含有return等語句,想一想替換後,會變成什麼樣子。
宏的返回值的兩種形式:
1 操作符。
#define Max(a,b) (((a)>(b))(a):(b))
#define add(a,b) ((a)+(b))
2 將返回值賦值給一個額外的形參,這個形參就是返回值。
#define cal(a,b,c) {c=a+b;}
一個非常有意思的例子:
定義一個求最大值的宏。
可能會這麼寫:#define Max(a,b) ((a)>(b) ?a):(b))
這麼做可能對於大多數情況是沒有錯誤的,但是其實這麼做是不嚴謹的。例如:
#define Max(a,b) ((a)>(b)? (a):(b))
int fun(int *a)
{
*a=*a+1;
return *a;
}
main()
{
int a=1,b=2,c;
c=Max(a,fun(&b));
}//我們想得到的c的值應該是3,但實際會發現c的值是4.
因爲首先我們替換:c=((a)>(fun(&b))? (a):(fun(&b)));
可以發現fun執行了兩次,b的值加了兩次變成了4.所以結果是4.
這裏給出一個嚴謹的做法:
使得參數只被執行一次。
#define Max(a,b) ({\
typeof(a) _a=(a);\
typeof(b) _b=(b);\
(_a>_b)? _x : _y; })
這樣就不會有上述的問題了。
注意:({...})的作用是將內部的幾條語句中最後一條的值返回,它也允許在內部聲明變量(因爲它通過大括號組成了一個局部Scope)。用此可以達到return的目的。
!!注:這裏使用了typeof,它是c的一個新擴展。而在vs2005,2010,2013中都無法使用。只能在在線編譯器下執行,結果是對的。
觀察發現:vs中不識別關鍵字typeof了。在C++中可用decltype實現相似功能,求某個變量的類型。而且vs中也不可以有這樣的({...})的東西了。要麼#define.. () 要麼#define .. {}。
所以上面的做法可以改成:
#define MIN(X,Y,M) {\
decltype(X)x_ = (X);\
decltype(Y)y_ = (Y);\
M=(x_ < y_) ? x_ : y_; }
使用時:int a=1,b=2,c; Max(a,b,c);c爲返回值,不參與運算。
#與##與#@在#define中的用法:
#的意思是不展開參數
如果在token-string 中出現以#開頭,意思是:不展開參數,直接替換。
如果在token-string 中出現不以#開頭,意思是:展開參數,直接替換。
例如:
#define f(a) a+1
#define T(a) #a
#define H(a) a
T(f(a))->f(a)->a+1
H(f(a))->H(a+1)->a+1
雖然結果一樣,但是過程不一樣。
##的意思是字符串連接符
例如:
#define f(a,b) a##b##lobe
結果就是ablobe
注意:##不能出現在開頭,也不能出現在結尾。只能出現在中間。
#@字符化運算符
Microsoft 專用
charizing 運算符只能與宏的參數一起使用。 如果宏的定義中的形參前有 #@,則會在擴展宏時用單引號括起實參並將其視爲一個字符。
#define makechar(x) #@x
==
char a= makechar(x);
例如:
#define H(x) #@x
cout<<H(a)<<endl;
輸出結果:a
cout<<H(ab)<<endl;
輸出結果:24930
註解:就是相當於把#@後面的實參變成一個字符型的字符。