带参数的宏定义
不是進(jìn)行簡(jiǎn)單的字符串替換,還要進(jìn)行參數(shù)替換。其定義的一般形式為
#define 宏名(參數(shù)表) 字符串
字符串中包含在括弧中所指定的參數(shù)。如:
#define S(a,b) a*b
area=S(3,2);
定義矩形面積S,a 和 b 是邊長(zhǎng)。在程序中用了S(3,2),把3、2分別代替宏定義中的形式參數(shù)a、b,即用 3*2 代替 S(3,2)。因此賦值語(yǔ)句展開(kāi)為
area=3*2;
對(duì)帶參的宏定義是這樣展開(kāi)轉(zhuǎn)換的:在程序中如果有帶實(shí)參的宏(如S(3,2)),則按 #define 命令行中指定的字符串從左到右進(jìn)行置換。如果串中包含宏中的形參(如a、b),則將程序語(yǔ)句中相應(yīng)的實(shí)參(可以是常量、變量或表達(dá)式)代替形參。如果宏定義中的字符串中的字符不是參數(shù)字符(如 a*b 中的 * 號(hào)),則保留。這樣就形成了置換的字符串,見(jiàn)右圖。
【例1】
#define PI 3.1415926
#define S(r) PI*r*r
main(){
???float a,area;
???a=3.6;
???area=S(a);
???printf("r=%f\narea=%f\n",a,area);
}
運(yùn)行結(jié)果如下:
r=3.600000
area=40.715038
賦值語(yǔ)句"area=S(a)";經(jīng)宏展開(kāi)后為
area=3.1415926*a*a;
說(shuō)明:
(1) 對(duì)帶參數(shù)的宏的展開(kāi)只是將語(yǔ)句中的宏名后面括號(hào)內(nèi)的實(shí)參字符串代替 #define 命令行中的形參。例1中語(yǔ)句中有S(a),在展開(kāi)時(shí),找到 #define 命令行中的 S(r),將 S(a) 中的實(shí)參 a 代替宏定義中的字符串“PI*r*r”中的形參r,得到PI*a*a。這是容易理解而且不會(huì)發(fā)生什么問(wèn)題的。但是,如果有以下語(yǔ)句:
area=S(a+b);
這時(shí)把實(shí)參 a+b 代替 PI*r*r 中的形參r,成為
area=PI*a+b*a+b;
請(qǐng)注意在 a+b 外面沒(méi)有括弧,顯然這與程序設(shè)計(jì)者的原意不符。原意希望得到
area=PI*(a+b)*(a+b);
為了得到這個(gè)結(jié)果,應(yīng)當(dāng)在定義時(shí),在字符串中的形式參數(shù)外面加一個(gè)括弧。即
#define S(r) PI*(r)*(r)
在對(duì) S(a+b) 進(jìn)行宏展開(kāi)時(shí),將 a+b 代替 r,就成了
PI*(a+b)*(a+b)
這就達(dá)到了目的。
(2) 在宏定義時(shí),在宏名與帶參數(shù)的括弧之間不應(yīng)加空格,否則將空格以后的字符都作為替代字符串的一部分。例如,如果有
#define S (r) PI*r*r
被認(rèn)為 S 是符號(hào)常量(不帶參的宏名),它代表字符串“(r) PI*r*r”。如果在語(yǔ)句中有
area=S (a);
則被展開(kāi)為
area=(r) PI*r*r (a);
顯然不對(duì)了。
有些讀者容易把帶參數(shù)的宏和函數(shù)混淆。的確,它們之間有一定類似之處,在調(diào)用函數(shù)時(shí)也是在函數(shù)名后的括弧內(nèi)寫(xiě)實(shí)參,也要求實(shí)參與形參的數(shù)目相等。但是帶參的宏定義與函數(shù)是不同的。主要有:
(1) 函數(shù)調(diào)用時(shí),先求出實(shí)參表達(dá)式的值,然后代入形參。而使用帶參的宏只是進(jìn)行簡(jiǎn)單的字符替換。例如上面的 S(a+b),在宏展開(kāi)時(shí)并不求 a+b 的值,而只將實(shí)參字符“a+b”代替形參r。
(2) 函數(shù)調(diào)用是在程序運(yùn)行時(shí)處理的,為形參分配臨時(shí)的內(nèi)存單元。而宏展開(kāi)則是在編譯前進(jìn)行的,在展開(kāi)時(shí)并不分配內(nèi)存單元,不進(jìn)行值的傳遞處理,也沒(méi)有“返回值”的概念。
(3) 對(duì)函數(shù)中的實(shí)參和形參都要定義類型,二者的類型要求一致,如不一致,應(yīng)進(jìn)行類型轉(zhuǎn)換。而宏不存在類型問(wèn)題,宏名無(wú)類型,它的參數(shù)也無(wú)類型,只是一個(gè)符號(hào)代表,展開(kāi)時(shí)代入指定的字符串即可。宏定義時(shí),字符串可以是任何類型的數(shù)據(jù)。例如:
#define CHAR1 CHINA (字符)
#define a 3.6 (數(shù)值)
CHAR1 和 a 不需要定義類型,它們不是變量,在程序中凡遇 CHAR1 均以 CHINA 代之;凡遇 a 均以 3.6 代之,顯然不需定義類型。同樣,對(duì)帶參的宏:
#define S(r) PI*r*r
r 也不是變量,如果在語(yǔ)句中有 S(3.6),則展開(kāi)后為 PI*3.6*3.6,語(yǔ)句中并不出現(xiàn)r。當(dāng)然也不必定義 r 的類型。
(4) 調(diào)用函數(shù)只可得到一個(gè)返回值,而用宏可以設(shè)法得到幾個(gè)結(jié)果。
【例2】
#define PI 3.1415926
#define CIRCLE(R,L,S,V) L=2*PI*R;S=PI*R*R;V=4.0/3.0*PI*R*R*R
main(){
???float r,l,s,v;
???scanf("%f",&r);
???CIRCLE(r,l,s,v);
???printf("r=%.2f,l=%.2f,s=%.2f,v=%.2f\n",r,l,s,v);
}
經(jīng)預(yù)編譯宏展開(kāi)后的程序如下:
main(){
???float r,l,s,v;
???scanf("%f",&r);
???l=2*3.1415926*r;s=3.1415926*r*r;v=4.0/3.0*3.1415926*r*r*r;
???printf("r=%.2f,l=%.2f,s=%.2f,v=%.2f\n",r,l,s,v);
}
請(qǐng)注意,實(shí)參 r 的值已知,可以從宏帶回3個(gè)值(l,s,v)。其實(shí),只不過(guò)是字符代替而已,將字符r代替R,l代替L,s代替S,v代替V,而并未在宏展開(kāi)時(shí)求出l、s、v的值。
(5) 使用宏次數(shù)多時(shí),宏展開(kāi)后源程序長(zhǎng),因?yàn)槊空归_(kāi)一次都使程序增長(zhǎng),而函數(shù)調(diào)用不使源程序變長(zhǎng)。
(6) 宏替換不占運(yùn)行時(shí)間,只占編譯時(shí)間。而函數(shù)調(diào)用則占運(yùn)行時(shí)間(分配單元、保留現(xiàn)場(chǎng)、值傳遞、返回)。
一般用宏來(lái)代表簡(jiǎn)短一的表達(dá)式比較合適。有些問(wèn)題,用宏和函數(shù)都可以。如:
#define MAX(x,y) (x)>(y)?(x):(y)
main(){
int a,b,c,d,t;
┊
t=MAX(a+b,c+d);
┊
}
賦值語(yǔ)句展開(kāi)后為
t=(a+b)>(c+d)?(a+b):(c+d);
注意:MAX不是函數(shù),這里只有一個(gè) main 函數(shù),在 main 函數(shù)中就能求出 t 的值。
這個(gè)問(wèn)題也可用函數(shù)來(lái)求:
int max(int x,int y){
return(x>y?x:y);
}
main(){
int a,b,c,d,t;
┊
t=max(a+b,c+d);
┊
}
max是函數(shù),在 main 函數(shù)中調(diào)用 max 函數(shù)才能求出 t 的值。
請(qǐng)仔細(xì)分析以上兩種方法。
如果善于利用宏定義,可以實(shí)現(xiàn)程序的簡(jiǎn)化,如事先將程序中的“輸出格式”定義好,以減少在輸出語(yǔ)句中每次都要寫(xiě)出具體的輸出格式的麻煩。
【例3】
#define PR printf
#define NL "\n"
#define D "%d"
#define D1 D NL
#define D2 D D NL
#define D3 D D D NL
#define D4 D D D D NL
#define S "%s"
main(){
???int a,b,c,d;
???char string[]="CHINA";
???a=1;b=2;c=3;d=4;
???PR(D1,a);
???PR(D2,a,b);
???PR(D3,a,b,c);
???PR(D4,a,b,c,d);
???PR(S,string);
}
運(yùn)行時(shí)輸出以下結(jié)果:
1
12
123
1234
CHINA
程序中用 PR 代表 printf。以 NL 代表執(zhí)行一次“換行”操作。以 D 代表輸出一個(gè)整型數(shù)據(jù)的格式符。以 D1 代表輸出完1個(gè)整數(shù)后換行,D2 代表輸出2個(gè)整數(shù)后換行,D3 代表輸出3個(gè)整數(shù)后換行,D4 代表輸出4個(gè)整數(shù)后換行。以 S 代表輸出一個(gè)字符串的格式符。可以看到,程序中寫(xiě)輸出語(yǔ)句就比較簡(jiǎn)單了,只要根據(jù)需要選擇已定義的輸出格式即可,連 printf 都可以簡(jiǎn)寫(xiě)為PR。
可以參照例3,寫(xiě)出各種輸入輸出的格式(例如實(shí)型、長(zhǎng)整型、十六進(jìn)制整數(shù)、八進(jìn)制整數(shù)、字符型等),把它們單獨(dú)編成一個(gè)文件,它相當(dāng)一個(gè)“格式庫(kù)”,用 #include 命令把它“包括”到自己所編的程序中,用戶就可以根據(jù)情況各取所需了。顯然在寫(xiě)大程序時(shí),這樣做是很方便的。
不帶參數(shù)的宏定義
#define 宏名(參數(shù)表) 字符串
字符串中包含在括弧中所指定的參數(shù)。如:
#define S(a,b) a*b
area=S(3,2);
定義矩形面積S,a 和 b 是邊長(zhǎng)。在程序中用了S(3,2),把3、2分別代替宏定義中的形式參數(shù)a、b,即用 3*2 代替 S(3,2)。因此賦值語(yǔ)句展開(kāi)為
area=3*2;
對(duì)帶參的宏定義是這樣展開(kāi)轉(zhuǎn)換的:在程序中如果有帶實(shí)參的宏(如S(3,2)),則按 #define 命令行中指定的字符串從左到右進(jìn)行置換。如果串中包含宏中的形參(如a、b),則將程序語(yǔ)句中相應(yīng)的實(shí)參(可以是常量、變量或表達(dá)式)代替形參。如果宏定義中的字符串中的字符不是參數(shù)字符(如 a*b 中的 * 號(hào)),則保留。這樣就形成了置換的字符串,見(jiàn)右圖。
【例1】
#define PI 3.1415926
#define S(r) PI*r*r
main(){
???float a,area;
???a=3.6;
???area=S(a);
???printf("r=%f\narea=%f\n",a,area);
}
運(yùn)行結(jié)果如下:
r=3.600000
area=40.715038
賦值語(yǔ)句"area=S(a)";經(jīng)宏展開(kāi)后為
area=3.1415926*a*a;
說(shuō)明:
(1) 對(duì)帶參數(shù)的宏的展開(kāi)只是將語(yǔ)句中的宏名后面括號(hào)內(nèi)的實(shí)參字符串代替 #define 命令行中的形參。例1中語(yǔ)句中有S(a),在展開(kāi)時(shí),找到 #define 命令行中的 S(r),將 S(a) 中的實(shí)參 a 代替宏定義中的字符串“PI*r*r”中的形參r,得到PI*a*a。這是容易理解而且不會(huì)發(fā)生什么問(wèn)題的。但是,如果有以下語(yǔ)句:
area=S(a+b);
這時(shí)把實(shí)參 a+b 代替 PI*r*r 中的形參r,成為
area=PI*a+b*a+b;
請(qǐng)注意在 a+b 外面沒(méi)有括弧,顯然這與程序設(shè)計(jì)者的原意不符。原意希望得到
area=PI*(a+b)*(a+b);
為了得到這個(gè)結(jié)果,應(yīng)當(dāng)在定義時(shí),在字符串中的形式參數(shù)外面加一個(gè)括弧。即
#define S(r) PI*(r)*(r)
在對(duì) S(a+b) 進(jìn)行宏展開(kāi)時(shí),將 a+b 代替 r,就成了
PI*(a+b)*(a+b)
這就達(dá)到了目的。
(2) 在宏定義時(shí),在宏名與帶參數(shù)的括弧之間不應(yīng)加空格,否則將空格以后的字符都作為替代字符串的一部分。例如,如果有
#define S (r) PI*r*r
被認(rèn)為 S 是符號(hào)常量(不帶參的宏名),它代表字符串“(r) PI*r*r”。如果在語(yǔ)句中有
area=S (a);
則被展開(kāi)為
area=(r) PI*r*r (a);
顯然不對(duì)了。
有些讀者容易把帶參數(shù)的宏和函數(shù)混淆。的確,它們之間有一定類似之處,在調(diào)用函數(shù)時(shí)也是在函數(shù)名后的括弧內(nèi)寫(xiě)實(shí)參,也要求實(shí)參與形參的數(shù)目相等。但是帶參的宏定義與函數(shù)是不同的。主要有:
(1) 函數(shù)調(diào)用時(shí),先求出實(shí)參表達(dá)式的值,然后代入形參。而使用帶參的宏只是進(jìn)行簡(jiǎn)單的字符替換。例如上面的 S(a+b),在宏展開(kāi)時(shí)并不求 a+b 的值,而只將實(shí)參字符“a+b”代替形參r。
(2) 函數(shù)調(diào)用是在程序運(yùn)行時(shí)處理的,為形參分配臨時(shí)的內(nèi)存單元。而宏展開(kāi)則是在編譯前進(jìn)行的,在展開(kāi)時(shí)并不分配內(nèi)存單元,不進(jìn)行值的傳遞處理,也沒(méi)有“返回值”的概念。
(3) 對(duì)函數(shù)中的實(shí)參和形參都要定義類型,二者的類型要求一致,如不一致,應(yīng)進(jìn)行類型轉(zhuǎn)換。而宏不存在類型問(wèn)題,宏名無(wú)類型,它的參數(shù)也無(wú)類型,只是一個(gè)符號(hào)代表,展開(kāi)時(shí)代入指定的字符串即可。宏定義時(shí),字符串可以是任何類型的數(shù)據(jù)。例如:
#define CHAR1 CHINA (字符)
#define a 3.6 (數(shù)值)
CHAR1 和 a 不需要定義類型,它們不是變量,在程序中凡遇 CHAR1 均以 CHINA 代之;凡遇 a 均以 3.6 代之,顯然不需定義類型。同樣,對(duì)帶參的宏:
#define S(r) PI*r*r
r 也不是變量,如果在語(yǔ)句中有 S(3.6),則展開(kāi)后為 PI*3.6*3.6,語(yǔ)句中并不出現(xiàn)r。當(dāng)然也不必定義 r 的類型。
(4) 調(diào)用函數(shù)只可得到一個(gè)返回值,而用宏可以設(shè)法得到幾個(gè)結(jié)果。
【例2】
#define PI 3.1415926
#define CIRCLE(R,L,S,V) L=2*PI*R;S=PI*R*R;V=4.0/3.0*PI*R*R*R
main(){
???float r,l,s,v;
???scanf("%f",&r);
???CIRCLE(r,l,s,v);
???printf("r=%.2f,l=%.2f,s=%.2f,v=%.2f\n",r,l,s,v);
}
經(jīng)預(yù)編譯宏展開(kāi)后的程序如下:
main(){
???float r,l,s,v;
???scanf("%f",&r);
???l=2*3.1415926*r;s=3.1415926*r*r;v=4.0/3.0*3.1415926*r*r*r;
???printf("r=%.2f,l=%.2f,s=%.2f,v=%.2f\n",r,l,s,v);
}
請(qǐng)注意,實(shí)參 r 的值已知,可以從宏帶回3個(gè)值(l,s,v)。其實(shí),只不過(guò)是字符代替而已,將字符r代替R,l代替L,s代替S,v代替V,而并未在宏展開(kāi)時(shí)求出l、s、v的值。
(5) 使用宏次數(shù)多時(shí),宏展開(kāi)后源程序長(zhǎng),因?yàn)槊空归_(kāi)一次都使程序增長(zhǎng),而函數(shù)調(diào)用不使源程序變長(zhǎng)。
(6) 宏替換不占運(yùn)行時(shí)間,只占編譯時(shí)間。而函數(shù)調(diào)用則占運(yùn)行時(shí)間(分配單元、保留現(xiàn)場(chǎng)、值傳遞、返回)。
一般用宏來(lái)代表簡(jiǎn)短一的表達(dá)式比較合適。有些問(wèn)題,用宏和函數(shù)都可以。如:
#define MAX(x,y) (x)>(y)?(x):(y)
main(){
int a,b,c,d,t;
┊
t=MAX(a+b,c+d);
┊
}
賦值語(yǔ)句展開(kāi)后為
t=(a+b)>(c+d)?(a+b):(c+d);
注意:MAX不是函數(shù),這里只有一個(gè) main 函數(shù),在 main 函數(shù)中就能求出 t 的值。
這個(gè)問(wèn)題也可用函數(shù)來(lái)求:
int max(int x,int y){
return(x>y?x:y);
}
main(){
int a,b,c,d,t;
┊
t=max(a+b,c+d);
┊
}
max是函數(shù),在 main 函數(shù)中調(diào)用 max 函數(shù)才能求出 t 的值。
請(qǐng)仔細(xì)分析以上兩種方法。
如果善于利用宏定義,可以實(shí)現(xiàn)程序的簡(jiǎn)化,如事先將程序中的“輸出格式”定義好,以減少在輸出語(yǔ)句中每次都要寫(xiě)出具體的輸出格式的麻煩。
【例3】
#define PR printf
#define NL "\n"
#define D "%d"
#define D1 D NL
#define D2 D D NL
#define D3 D D D NL
#define D4 D D D D NL
#define S "%s"
main(){
???int a,b,c,d;
???char string[]="CHINA";
???a=1;b=2;c=3;d=4;
???PR(D1,a);
???PR(D2,a,b);
???PR(D3,a,b,c);
???PR(D4,a,b,c,d);
???PR(S,string);
}
運(yùn)行時(shí)輸出以下結(jié)果:
1
12
123
1234
CHINA
程序中用 PR 代表 printf。以 NL 代表執(zhí)行一次“換行”操作。以 D 代表輸出一個(gè)整型數(shù)據(jù)的格式符。以 D1 代表輸出完1個(gè)整數(shù)后換行,D2 代表輸出2個(gè)整數(shù)后換行,D3 代表輸出3個(gè)整數(shù)后換行,D4 代表輸出4個(gè)整數(shù)后換行。以 S 代表輸出一個(gè)字符串的格式符。可以看到,程序中寫(xiě)輸出語(yǔ)句就比較簡(jiǎn)單了,只要根據(jù)需要選擇已定義的輸出格式即可,連 printf 都可以簡(jiǎn)寫(xiě)為PR。
可以參照例3,寫(xiě)出各種輸入輸出的格式(例如實(shí)型、長(zhǎng)整型、十六進(jìn)制整數(shù)、八進(jìn)制整數(shù)、字符型等),把它們單獨(dú)編成一個(gè)文件,它相當(dāng)一個(gè)“格式庫(kù)”,用 #include 命令把它“包括”到自己所編的程序中,用戶就可以根據(jù)情況各取所需了。顯然在寫(xiě)大程序時(shí),這樣做是很方便的。
版權(quán)聲明:此文章為廠商在線—軟件直銷網(wǎng)(www.soft568.com)原創(chuàng),如需轉(zhuǎn)載請(qǐng)保留此鏈接,并勿隨意改動(dòng)文章內(nèi)容!
不帶參數(shù)的宏定義
http://www.doc88.com/p-992520052502.html
不帶參數(shù)的宏定義
總結(jié)
- 上一篇: 编程制作动态壁纸的思路_Android自
- 下一篇: VS 2015 卸载所有组件工具