c++中define用法
define在c++語言中用法比較多,這裏對其進行整理。
1.無參宏定義
無參宏的宏名後不帶參數。
其定義的一般形式爲:
#define 標識符 字符串
- 1
- 1
其中的“#”表示這是一條預處理命令。凡是以“#”開頭的均爲預處理命令。“define”爲宏定義命令。“標識符”爲所定義的宏名。“字符串”可以是常數、表達式、格式串等。
例如:
#define MAXNUM 99999
- 1
- 1
這樣MAXNUM就被簡單的定義爲99999。
2.有參宏定義
C++語言允許宏帶有參數。在宏定義中的參數稱爲形式參數,在宏調用中的參數稱爲實際參數。
對帶參數的宏,在調用中,不僅要宏展開,而且要用實參去代換形參。
帶參宏定義的一般形式爲:
#define 宏名(形參表) 字符串
- 1
- 1
在字符串中含有各個形參。在使用時調用帶參宏調用的一般形式爲:宏名(實參表);
例如:
#define add(x, y) (x + y)
int main()
{
cout << "1 plus 1 is " << add(1, 1.5) << ".\n";
//輸出“1 plus 1 is 2.5.”
system("pause");
return(0);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
這個“函數”定義了加法,但是該“函數”沒有類型檢查,有點類似模板,但沒有模板安全,可以看做一個簡單的模板。
注意:該“函數”定義爲(a + b),在這裏加括號的原因是,宏定義只是在預處理階段做了簡單的替換,如果單純的替換爲a + b時,當你使用5 * add(2, 3)時,被替換爲5 * 2 + 3,值爲13,而非5 * (2 + 3),值爲25。
3.宏定義中的特殊操作符
define 中的特殊操作符有#,##和… and __VA_ARGS__
(1)#
假如希望在字符串中包含宏參數,ANSI C允許這樣作,在類函數宏的替換部分,#符號用作一個預處理運算符,它可以把語言符號轉化程字符串。例如,如果x是一個宏參量,那麼#x可以把參數名轉化成相應的字符串。該過程稱爲字符串化。
例如:
#incldue <stdio.h>
#define PSQR(x) printf("the square of" #x "is %d.\n",(x)*(x))
int main(void)
{
int y =4;
PSQR(y);
//輸出:the square of y is 16.
PSQR(2+4);
//輸出:the square of 2+4 is 36.
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
(2)##
##運算符可以用於類函數宏的替換部分。另外,##還可以用於類對象宏的替換部分。這個運算符把兩個語言符號組合成單個語言符號。
例如:
#include <stdio.h>
#define XNAME(n) x##n
#define PXN(n) printf("x"#n" = %d\n",x##n)
int main(void)
{
int XNAME(1)=12;//int x1=12;
PXN(1);//printf("x1 = %d\n", x1);
//輸出:x1=12
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
(3)可變參數宏 …和__VA_ARGS__
__VA_ARGS__ 是一個可變參數的宏,很少人知道這個宏,這個可變參數的宏是新的C99規範中新增的,目前似乎只有gcc支持(VC6.0的編譯器不支持)。
實現思想就是宏定義中參數列表的最後一個參數爲省略號(也就是三個點)。這樣預定義宏__VA_ARGS__就可以被用在替換部分中,替換省略號所代表的字符串。
例如:
#define PR(...) printf(__VA_ARGS__)
int main()
{
int wt=1,sp=2;
PR("hello\n");
//輸出:hello
PR("weight = %d, shipping = %d",wt,sp);
//輸出:weight = 1, shipping = 2
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
省略號只能代替最後面的宏參數。
#define W(x,…,y)錯誤!
但是支持#define W(x, …),此時傳入的參數個數必須能夠匹配。
這裏再介紹幾個系統的宏:
1) __VA_ARGS__ 是一個可變參數的宏,很少人知道這個宏,這個可變參數的宏是新的C99規範中新增的,目前似乎只有gcc支持(VC6.0的編譯器不支持)。宏前面加上##的作用在於,當可變參數的個數爲0時,這裏的##起到把前面多餘的”,”去掉的作用,否則會編譯出錯, 你可以試試。
2) __FILE__ 宏在預編譯時會替換成當前的源文件名
3) __LINE__宏在預編譯時會替換成當前的行號
4) __FUNCTION__宏在預編譯時會替換成當前的函數名稱
4.宏定義中的多行定義
非常經典。
#define MACRO(arg1, arg2) do { /
/* declarations */ /
stmt1; /
stmt2; /
/* ... */ /
} while(0) /* (no trailing ; ) */
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
記得要在每一個換行的時候加上一個”/”
5.宏定義中的條件編譯
在大規模的開發過程中,特別是跨平臺和系統的軟件裏,define最重要的功能是條件編譯。
#ifdef WINDOWS
......
(#else)
......
#endif
#ifdef LINUX
......
(#else)
......
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
可以在編譯的時候通過#define設置編譯環境。
6.如何取消宏
//定義宏
#define [MacroName] [MacroValue]
//取消宏
#undef [MacroName]
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
7.防止重複包含頭文件
由於頭文件包含可以嵌套,那麼C文件就有可能包含多次同一個頭文件,就可能出現重複定義的問題的。
通過條件編譯開關來避免重複包含(重複定義)
例如:
#ifndef __headerfileXXX__
#define __headerfileXXX__
…
文件內容
…
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
小結及說明
1) 宏定義是用宏名來表示一個字符串,在宏展開時又以該字符串取代宏名,這只是一種簡單的代換,字符串中可以含任何字符,可以是常數,也可以是表達式,預處理程序對它不作任何檢查。如有錯誤,只能在編譯已被宏展開後的源程序時發現。
2) 宏定義不是說明或語句,在行末不必加分號,如加上分號則連分號也一起置換。
3) 宏定義必須寫在函數之外,其作用域爲宏定義命令起到源程序結束。如要終止其作用域可使用#undef命令。只要函數定義在#undefine之後,則函數無法使用#define的內容。
4) 宏名在源程序中若用引號括起來,則預處理程序不對其作宏代換。
5) 宏定義允許嵌套,在宏定義的字符串中可以使用已經定義的宏名。在宏展開時由預處理程序層層代換。
例如:
#define PI 3.1415926
#define S PI*y*y /* PI是已定義的宏名*/
- 1
- 2
- 1
- 2
6) 習慣上宏名用大寫字母表示,以便於與變量區別。但也允許用小寫字母。
7) 可用宏定義表示數據類型,使書寫方便。
應注意用宏定義表示數據類型和用typedef定義數據說明符的區別。
宏定義只是簡單的字符串代換,是在預處理完成的,而typedef是在編譯時處理的,它不是作簡單的代換,而是對類型說明符重新命名。被命名的標識符具有類型定義說明的功能。
請看下面的例子:
#define PIN1 int *
typedef (int *) PIN2;
- 1
- 2
- 1
- 2
從形式上看這兩者相似, 但在實際使用中卻不相同。
下面用PIN1,PIN2說明變量時就可以看出它們的區別:
PIN1 a,b;在宏代換後變成:
int *a,b;
表示a是指向整型的指針變量,而b是整型變量。
然而:
PIN2 a,b;
表示a,b都是指向整型的指針變量。因爲PIN2是一個類型說明符。由這個例子可見,宏定義雖然也可表示數據類型, 但畢竟是作字符代換。在使用時要分外小心,以避出錯。
8) 對“輸出格式”作宏定義,可以減少書寫麻煩。
例如:
#define P printf
#define D "%d\n"
#define F "%f\n"
main(){
int a=5, c=8, e=11;
float b=3.8, d=9.7, f=21.08;
P(D F,a,b);
P(D F,c,d);
P(D F,e,f);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
9)帶參宏定義中,宏名和形參表之間不能有空格出現。
10)在帶參宏定義中,形式參數不分配內存單元,因此不必作類型定義。而宏調用中的實參有具體的值。要用它們去代換形參,因此必須作類型說明。這是與函數中的情況不同的。在函數中,形參和實參是兩個不同的量,各有自己的作用域,調用時要把實參值賦予形參,進行“值傳遞”。而在帶參宏中,只是符號代換,不存在值傳遞的問題。
11)在宏定義中的形參是標識符,而宏調用中的實參可以是表達式。