带参数的宏定义
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
带参数的宏定义不仅要进行字符串的替换,而且还要进行参数替换,一般形式为:
#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
相关文章推荐
- linux c 定义打印时间/文件名/行/函数日志的可变参数宏定义,如果需要的话可以参考
- C99标准之宏定义_可变参数宏_#_##
- 带参数的宏定义(宏函数)
- C语言可变参数在宏定义中的应用
- C/C++宏定义的可变参数
- 宏定义中的特殊参数(#、##、...和__VA_ARGS__) 【转】
- 宏定义有无参数宏定义和带参数宏定义两种
- 如何把宏定义中的参数转为字符串
- C语言可变参数在宏定义中的应用
- 宏定义及带参数的宏定义
- 宏定义函数指针类型&函数返回左值类值 1。宏定义不分配内存,变量定义分配内存。 2。宏名和参数的括号间不能有空格 3。宏替换只作替换,不做计算,不做表达式求解 //下面是正确的标准的写法 typedef int(FUNC1)(int in); ty
- gcc中利用-D参数进行宏定义
- 记录log宏定义可变参数的几种处理方式
- 宏定义中的特殊参数(#、##、...和__VA_ARGS__)
- C语言可变参数及stdarg.h中的三个宏定义
- snprintf连续打印封装:可变参数的宏定义
- 可变参数的宏定义
- 带格式化参数的strcat宏定义
- 宏定义中的特殊参数(#、##、...和__VA_ARGS__)+二叉查找树
- 带参数的宏定义应该怎么写,参数不能加括号