您的位置:首页 > 其它

带参数的宏定义

2012-12-09 15:20 162 查看
带参数的宏定义
带参数的宏定义不仅要进行字符串的替换,而且还要进行参数替换,一般形式为:

#define <宏名>(<参数表>)<带参数的替换序列>

其中,参数为形参。

宏展开过程:程序中若有带实参的宏,则按#define指定的替换序列从左至右进行替换。若宏定义中包含有形参,则用程序中相应的实参替换形参,其中实参可以是常量、变量或表达式;若宏定义的替换序列中的字符不是形参,则在替换时保留。

[例7.2]从键盘输入两个数,输出较小的数。

#include “stdio.h”

#define MIN(a,b) ((a)<(b)?(a):(b))

main()

{

int x,y;

printf (“输入两个数”);

scanf (“%d,%d ”,&x,&y);

printf (“MIN=%d”,MIN(x,y));

}

以上程序执行时,用序列((x)<(y)?(x):(y))来替换MIN(x,y)。所以,可以输出两个数中的较小者。

对使用带参数的宏定义需要说明几点:

(1)对用宏定义定义的字符序列中的参数要用圆括号括起来,而且最好把整个字符串也用括号括起来,以保证在任何替换情况下都把宏定义作为一个整体,并且可以有一个合理的计算顺序,否则宏展开后,可能会出现意想不到的错误。如:

#define S(r) 3.14159* r* r



area=S(a+b);

经过宏展开变为:

area=3.14159* a+b* a+b;

显然是由于在进行宏定义时,对r没有加括号造成与设计的原意不符。那么,为了得到形如:

area=3.14159* (a+b) * (a+b);

就应该在宏定义时给字符序列中的形参加上括号,如;

#define S(r) 3.14159* (r) * (r)

(2)宏定义时,不要在宏名与带参数的括号之间加空格,否则会将空格后的字符都作为替换序列的一部分。如:

#define S (a,b) a* b

如果程序中有

mul= S(x,y)

则被展开为:

mul=(a,b)a* b(x,y)

(3)把函数和带参数的宏要区分开,虽然它们有相似之处,但它们是不同的,其区别见表7.1所示。

表7.1 函数和带参数之宏的区别

区 别 类 型

函 数 带参数的宏

是否计算实参的值 先计算出实参表达式的值,然后代替形参 不计算实参表达式的值,直接用实参进行简单的替换

何时进行处理、分配内存单元 在程序运行时进行值的处理、分配临时的内存单元, 编译时进行宏展开,不分配内存单元,不进行值的处理

类型要求 实参和形参要定义类型,且类型一致 不存在类型问题,只是一个符号表示,可以为任何类型

调用情况 函数的代码只作为一个拷贝存在,对程序较大、调用次数多的较合算,但调用函数时有一定数量的处理开销 在源代码中遇到宏定义时,都将其扩展为代码,程序调用几次宏就扩展为代码几次,但调用宏时没有处理的开销

函数和带参数的宏的区别:

1.函数调用时,先求出实参表达式的值,然后带入形参。而使用带参的宏只是进行简单的字符替换。

2.函数调用是在程序运行时处理的,分配临时的内存单元;而宏展开则是在编译时进行的,在展开时并不分配内存单元,不进行值的传递处理,也没有“返回值”的概念。

3.对函数中的实参和形参都要定义类型,二者的类型要求一致,如不一致,应进行类型转换;而宏不存在类型问题,宏名无类型,它的参数也无类型,只是一个符号代表,展开时带入指定的字符即可。宏定义时,字符串可以是任何类型的数据。

4.调用函数只可得到一个返回值,而用宏可以设法得到几个结果。

5.使用宏次数多时,宏展开后源程序长,因为每展开一次都使程序增长,而函数调用不使源程序变长。

6.宏替换不占运行时间,只占编译时间;而函数调用则占运行时间(分配单元、保留现场、值传递、返回)。
一般来说,用宏来代表简短的表达式比较合适。
有时使用宏时会引起理解错误:
例:
#i nclude<iostream.h>

#define max(a,b) ((a>b)?a:b)

void main()

{

int i=3,j=2;

cout<<max(++i,j)<<endl;

cout<<i<<" "<<j<<endl;

}
运行结果:
5
5 2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: