不是进行简单的字符串替换,还要进行参数替换。其定义的一般形式为
#define 宏名(参数表) 字符串
字符串中包含在括弧中所指定的参数。如:
#define S(a,b) a*b
area=S(3,2);
定义矩形面积S,a 和 b 是边长。在程序中用了S(3,2),把3、2分别代替宏定义中的形式参数a、b,即用 3*2 代替 S(3,2)。因此赋值语句展开为
area=3*2;
对带参的宏定义是这样展开转换的:在程序中如果有带实参的宏(如S(3,2)),则按 #define 命令行中指定的字符串从左到右进行置换。如果串中包含宏中的形参(如a、b),则将程序语句中相应的实参(可以是常量、变量或表达式)代替形参。如果宏定义中的字符串中的字符不是参数字符(如 a*b 中的 * 号),则保留。这样就形成了置换的字符串,见右图。
【例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);
}
运行结果如下:
r=3.600000
area=40.715038
赋值语句"area=S(a)";经宏展开后为
area=3.1415926*a*a;
说明:
(1) 对带参数的宏的展开只是将语句中的宏名后面括号内的实参字符串代替 #define 命令行中的形参。例1中语句中有S(a),在展开时,找到 #define 命令行中的 S(r),将 S(a) 中的实参 a 代替宏定义中的字符串“PI*r*r”中的形参r,得到PI*a*a。这是容易理解而且不会发生什么问题的。但是,如果有以下语句:
area=S(a+b);
这时把实参 a+b 代替 PI*r*r 中的形参r,成为
area=PI*a+b*a+b;
请注意在 a+b 外面没有括弧,显然这与程序设计者的原意不符。原意希望得到
area=PI*(a+b)*(a+b);
为了得到这个结果,应当在定义时,在字符串中的形式参数外面加一个括弧。即
#define S(r) PI*(r)*(r)
在对 S(a+b) 进行宏展开时,将 a+b 代替 r,就成了
PI*(a+b)*(a+b)
这就达到了目的。
(2) 在宏定义时,在宏名与带参数的括弧之间不应加空格,否则将空格以后的字符都作为替代字符串的一部分。例如,如果有
#define S (r) PI*r*r
被认为 S 是符号常量(不带参的宏名),它代表字符串“(r) PI*r*r”。如果在语句中有
area=S (a);
则被展开为
area=(r) PI*r*r (a);
显然不对了。
有些读者容易把带参数的宏和函数混淆。的确,它们之间有一定类似之处,在调用函数时也是在函数名后的括弧内写实参,也要求实参与形参的数目相等。但是带参的宏定义与函数是不同的。主要有:
(1) 函数调用时,先求出实参表达式的值,然后代入形参。而使用带参的宏只是进行简单的字符替换。例如上面的 S(a+b),在宏展开时并不求 a+b 的值,而只将实参字符“a+b”代替形参r。
(2) 函数调用是在程序运行时处理的,为形参分配临时的内存单元。而宏展开则是在编译前进行的,在展开时并不分配内存单元,不进行值的传递处理,也没有“返回值”的概念。
(3) 对函数中的实参和形参都要定义类型,二者的类型要求一致,如不一致,应进行类型转换。而宏不存在类型问题,宏名无类型,它的参数也无类型,只是一个符号代表,展开时代入指定的字符串即可。宏定义时,字符串可以是任何类型的数据。例如:
#define CHAR1 CHINA (字符)
#define a 3.6 (数值)
CHAR1 和 a 不需要定义类型,它们不是变量,在程序中凡遇 CHAR1 均以 CHINA 代之;凡遇 a 均以 3.6 代之,显然不需定义类型。同样,对带参的宏:
#define S(r) PI*r*r
r 也不是变量,如果在语句中有 S(3.6),则展开后为 PI*3.6*3.6,语句中并不出现r。当然也不必定义 r 的类型。
(4) 调用函数只可得到一个返回值,而用宏可以设法得到几个结果。
【例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);
}
经预编译宏展开后的程序如下:
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);
}
请注意,实参 r 的值已知,可以从宏带回3个值(l,s,v)。其实,只不过是字符代替而已,将字符r代替R,l代替L,s代替S,v代替V,而并未在宏展开时求出l、s、v的值。
(5) 使用宏次数多时,宏展开后源程序长,因为每展开一次都使程序增长,而函数调用不使源程序变长。
(6) 宏替换不占运行时间,只占编译时间。而函数调用则占运行时间(分配单元、保留现场、值传递、返回)。
一般用宏来代表简短一的表达式比较合适。有些问题,用宏和函数都可以。如:
#define MAX(x,y) (x)>(y)?(x):(y)
main(){
int a,b,c,d,t;
┊
t=MAX(a+b,c+d);
┊
}
赋值语句展开后为
t=(a+b)>(c+d)?(a+b):(c+d);
注意:MAX不是函数,这里只有一个 main 函数,在 main 函数中就能求出 t 的值。
这个问题也可用函数来求:
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是函数,在 main 函数中调用 max 函数才能求出 t 的值。
请仔细分析以上两种方法。
如果善于利用宏定义,可以实现程序的简化,如事先将程序中的“输出格式”定义好,以减少在输出语句中每次都要写出具体的输出格式的麻烦。
【例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);
}
运行时输出以下结果:
1
12
123
1234
CHINA
程序中用 PR 代表 printf。以 NL 代表执行一次“换行”操作。以 D 代表输出一个整型数据的格式符。以 D1 代表输出完1个整数后换行,D2 代表输出2个整数后换行,D3 代表输出3个整数后换行,D4 代表输出4个整数后换行。以 S 代表输出一个字符串的格式符。可以看到,程序中写输出语句就比较简单了,只要根据需要选择已定义的输出格式即可,连 printf 都可以简写为PR。
可以参照例3,写出各种输入输出的格式(例如实型、长整型、十六进制整数、八进制整数、字符型等),把它们单独编成一个文件,它相当一个“格式库”,用 #include 命令把它“包括”到自己所编的程序中,用户就可以根据情况各取所需了。显然在写大程序时,这样做是很方便的。
#define 宏名(参数表) 字符串
字符串中包含在括弧中所指定的参数。如:
#define S(a,b) a*b
area=S(3,2);
定义矩形面积S,a 和 b 是边长。在程序中用了S(3,2),把3、2分别代替宏定义中的形式参数a、b,即用 3*2 代替 S(3,2)。因此赋值语句展开为
area=3*2;
对带参的宏定义是这样展开转换的:在程序中如果有带实参的宏(如S(3,2)),则按 #define 命令行中指定的字符串从左到右进行置换。如果串中包含宏中的形参(如a、b),则将程序语句中相应的实参(可以是常量、变量或表达式)代替形参。如果宏定义中的字符串中的字符不是参数字符(如 a*b 中的 * 号),则保留。这样就形成了置换的字符串,见右图。
【例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);
}
运行结果如下:
r=3.600000
area=40.715038
赋值语句"area=S(a)";经宏展开后为
area=3.1415926*a*a;
说明:
(1) 对带参数的宏的展开只是将语句中的宏名后面括号内的实参字符串代替 #define 命令行中的形参。例1中语句中有S(a),在展开时,找到 #define 命令行中的 S(r),将 S(a) 中的实参 a 代替宏定义中的字符串“PI*r*r”中的形参r,得到PI*a*a。这是容易理解而且不会发生什么问题的。但是,如果有以下语句:
area=S(a+b);
这时把实参 a+b 代替 PI*r*r 中的形参r,成为
area=PI*a+b*a+b;
请注意在 a+b 外面没有括弧,显然这与程序设计者的原意不符。原意希望得到
area=PI*(a+b)*(a+b);
为了得到这个结果,应当在定义时,在字符串中的形式参数外面加一个括弧。即
#define S(r) PI*(r)*(r)
在对 S(a+b) 进行宏展开时,将 a+b 代替 r,就成了
PI*(a+b)*(a+b)
这就达到了目的。
(2) 在宏定义时,在宏名与带参数的括弧之间不应加空格,否则将空格以后的字符都作为替代字符串的一部分。例如,如果有
#define S (r) PI*r*r
被认为 S 是符号常量(不带参的宏名),它代表字符串“(r) PI*r*r”。如果在语句中有
area=S (a);
则被展开为
area=(r) PI*r*r (a);
显然不对了。
有些读者容易把带参数的宏和函数混淆。的确,它们之间有一定类似之处,在调用函数时也是在函数名后的括弧内写实参,也要求实参与形参的数目相等。但是带参的宏定义与函数是不同的。主要有:
(1) 函数调用时,先求出实参表达式的值,然后代入形参。而使用带参的宏只是进行简单的字符替换。例如上面的 S(a+b),在宏展开时并不求 a+b 的值,而只将实参字符“a+b”代替形参r。
(2) 函数调用是在程序运行时处理的,为形参分配临时的内存单元。而宏展开则是在编译前进行的,在展开时并不分配内存单元,不进行值的传递处理,也没有“返回值”的概念。
(3) 对函数中的实参和形参都要定义类型,二者的类型要求一致,如不一致,应进行类型转换。而宏不存在类型问题,宏名无类型,它的参数也无类型,只是一个符号代表,展开时代入指定的字符串即可。宏定义时,字符串可以是任何类型的数据。例如:
#define CHAR1 CHINA (字符)
#define a 3.6 (数值)
CHAR1 和 a 不需要定义类型,它们不是变量,在程序中凡遇 CHAR1 均以 CHINA 代之;凡遇 a 均以 3.6 代之,显然不需定义类型。同样,对带参的宏:
#define S(r) PI*r*r
r 也不是变量,如果在语句中有 S(3.6),则展开后为 PI*3.6*3.6,语句中并不出现r。当然也不必定义 r 的类型。
(4) 调用函数只可得到一个返回值,而用宏可以设法得到几个结果。
【例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);
}
经预编译宏展开后的程序如下:
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);
}
请注意,实参 r 的值已知,可以从宏带回3个值(l,s,v)。其实,只不过是字符代替而已,将字符r代替R,l代替L,s代替S,v代替V,而并未在宏展开时求出l、s、v的值。
(5) 使用宏次数多时,宏展开后源程序长,因为每展开一次都使程序增长,而函数调用不使源程序变长。
(6) 宏替换不占运行时间,只占编译时间。而函数调用则占运行时间(分配单元、保留现场、值传递、返回)。
一般用宏来代表简短一的表达式比较合适。有些问题,用宏和函数都可以。如:
#define MAX(x,y) (x)>(y)?(x):(y)
main(){
int a,b,c,d,t;
┊
t=MAX(a+b,c+d);
┊
}
赋值语句展开后为
t=(a+b)>(c+d)?(a+b):(c+d);
注意:MAX不是函数,这里只有一个 main 函数,在 main 函数中就能求出 t 的值。
这个问题也可用函数来求:
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是函数,在 main 函数中调用 max 函数才能求出 t 的值。
请仔细分析以上两种方法。
如果善于利用宏定义,可以实现程序的简化,如事先将程序中的“输出格式”定义好,以减少在输出语句中每次都要写出具体的输出格式的麻烦。
【例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);
}
运行时输出以下结果:
1
12
123
1234
CHINA
程序中用 PR 代表 printf。以 NL 代表执行一次“换行”操作。以 D 代表输出一个整型数据的格式符。以 D1 代表输出完1个整数后换行,D2 代表输出2个整数后换行,D3 代表输出3个整数后换行,D4 代表输出4个整数后换行。以 S 代表输出一个字符串的格式符。可以看到,程序中写输出语句就比较简单了,只要根据需要选择已定义的输出格式即可,连 printf 都可以简写为PR。
可以参照例3,写出各种输入输出的格式(例如实型、长整型、十六进制整数、八进制整数、字符型等),把它们单独编成一个文件,它相当一个“格式库”,用 #include 命令把它“包括”到自己所编的程序中,用户就可以根据情况各取所需了。显然在写大程序时,这样做是很方便的。
版权声明:此文章为厂商在线—软件直销网(www.soft568.com)原创,如需转载请保留此链接,并勿随意改动文章内容!
不带参数的宏定义
http://www.doc88.com/p-992520052502.html
不带参数的宏定义