#define的用法體會

#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的一個新擴展。而在vs200520102013中都無法使用。只能在在線編譯器下執行,結果是對的。

觀察發現: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

註解:就是相當於把#@後面的實參變成一個字符型的字符。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章