C程序设计C程序设计 (48).pdf

上传人:刘静 文档编号:52870382 上传时间:2022-10-24 格式:PDF 页数:37 大小:619.13KB
返回 下载 相关 举报
C程序设计C程序设计 (48).pdf_第1页
第1页 / 共37页
C程序设计C程序设计 (48).pdf_第2页
第2页 / 共37页
点击查看更多>>
资源描述

《C程序设计C程序设计 (48).pdf》由会员分享,可在线阅读,更多相关《C程序设计C程序设计 (48).pdf(37页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、C C程序设计程序设计Programming in CProgramming in C编程任务的自动化编程任务的自动化3、带参数的宏定义4、编译器预定义宏C C程序设计程序设计程序设计程序设计3 35.1.2 5.1.2 带参数的宏定义带参数的宏定义带参数的宏定义的命令形式为:带参数的宏的引用形式为:#define 宏名(参数表)字符文本#define 宏名(参数表)字符文本宏名宏名(引用参数表引用参数表)4 45.1.2 5.1.2 带参数的宏定义带参数的宏定义其中:参数表允许多个参数,用逗号分隔,称为形式参数(不同于函数的形参概念)。字符文本中包含所指定的参数文本,出现次序和数目没有任何限

2、制。引用参数表与宏定义的形式参数要求一一对应。5 55.1.2 5.1.2 带参数的宏定义带参数的宏定义预处理时,预处理器先将宏引用的引用参数文本对应地替换宏定义字符文本中的参数,接下来进行宏替换,然后再进行编译。6 65.1.2 5.1.2 带参数的宏定义带参数的宏定义例如有宏定义形式参数按顺序为a和b,而程序代码:引用参数文本按顺序为x-y和x+y。#define max(a,b)(a)(b)?(a):(b)#define max(a,b)(a)(b)?(a):(b)L L=maxmax(x x-y y,x x+y y););/max宏引用/max宏引用7 75.1.2 5.1.2 带参数

3、的宏定义带参数的宏定义先将引用参数文本对应地替换字符文本中的参数,字符文本中其他内容不变,则字符文本置换为:因此预处理时宏替换为:(x x-y y)()(x x+y y)?(x x-y y):():(x x+y y)L L=(=(x x-y y)()(x x+y y)?(x x-y y):():(x x+y y)8 85.1.2 5.1.2 带参数的宏定义带参数的宏定义使用带参数的宏定义需要注意:(1)宏名与“(参数表)”之间不能有空白符,否则命令形式会被理解为不带参数的宏定义,而“(参数表)”是字符文本的一部分。9 95.1.2 5.1.2 带参数的宏定义带参数的宏定义例如:AREA为不带参

4、数的宏,“(r)PI*r*r”组成了它的字符文本,因此:展开为:显然是不对的。#define AREA(r)PI*r*r#define AREA(r)PI*r*rS S=AREAAREA(x x););/AREA宏引用/AREA宏引用S S=(=(r r)PIPI*r r*r r(x x)10105.1.2 5.1.2 带参数的宏定义带参数的宏定义(2)字符文本中的参数必须是由各种符号、空白符分隔出来的独立字符文本,例如:Aarg字符文本不会进行arg参数替换,因为Aarg是一个不可分割的整体。#define MSET1(arg)x=Aarg+2;#define MSET2(arg)x=A+a

5、rg;#define MSET1(arg)x=Aarg+2;#define MSET2(arg)x=A+arg;MSET1MSET1(1 1)/宏替换为 x=Aarg+2;arg没有被替换/宏替换为 x=Aarg+2;arg没有被替换MSET2MSET2(1 1)/宏替换为 x=A+1;arg已替换/宏替换为 x=A+1;arg已替换11115.1.2 5.1.2 带参数的宏定义带参数的宏定义(3)引用参数文本替换字符文本中的参数时,只是简单地做文本替换,某些表达式的宏定义中,这种简单处理可能会得到不符合原意的替换结果。12125.1.2 5.1.2 带参数的宏定义带参数的宏定义例如:如果宏引

6、用为:是正确的,但如果宏引用为:得到的宏扩展“x+y*x+y”显然与“(x+y)*(x+y)”原意不符。#define POWER(a)a*a#define POWER(a)a*a/计算a的平方/计算a的平方S S=POWERPOWER(x x););/宏替换为 S=x*x/宏替换为 S=x*xS S=POWERPOWER(x x+y y););/宏替换为 S=x+y*x+y/宏替换为 S=x+y*x+y13135.1.2 5.1.2 带参数的宏定义带参数的宏定义解决这个问题有两种方法:一是给引用参数文本加上括号,例如:S S=POWERPOWER(x x+y y););/宏替换为 S=(x+

7、y)*(x+y)/宏替换为 S=(x+y)*(x+y)14145.1.2 5.1.2 带参数的宏定义带参数的宏定义二是在宏定义时给字符文本中的参数加上括号,例如:实际编程中,第二种方法更稳妥。#define POWER(a)(a)*(a)#define POWER(a)(a)*(a)/计算a的平方/计算a的平方S S=POWERPOWER(x x+y y););/宏替换为 S=(x+y)*(x+y)/宏替换为 S=(x+y)*(x+y)15155.1.2 5.1.2 带参数的宏定义带参数的宏定义(4)无论是带参数的宏定义或是不带参数的宏定义,均可以使用行连接符“”得到多行宏定义,进而得到具有复

8、杂功能的宏。16165.1.2 5.1.2 带参数的宏定义带参数的宏定义例如:1#define PRINTSTAR(n)#define PRINTSTAR(n)2 int i,j;int i,j;3 for(i=1;i=n;i+)for(i=1;i=n;i+)4 for(j=1;j=i;j+)for(j=1;j=i;j+)5 printf(*);printf(*);6 printf(n);printf(n);7 8 17175.1.2 5.1.2 带参数的宏定义带参数的宏定义那么PRINTSTAR(5)宏引用的结果实际上是如下程序代码:1 2 intint i i,j j;3 forfor(i

9、 i=1 1;i i=5 5;i i+)+)4 forfor(j j=1 1;j j=i i;j j+)+)5 printfprintf(*);(*);6 printfprintf(nn););7 8 18185.1.2 5.1.2 带参数的宏定义带参数的宏定义这里外加一对花括号“”的目的是形成一个复合语句,局部区域变量,它们与外部不会有任何冲突。需要注意,宏定义的最后要连接一个空行,这样宏替换时才会有相应的换行。19195.1.2 5.1.2 带参数的宏定义带参数的宏定义PRINTSTAR(5)的运行结果为:*20205.1.2 5.1.2 带参数的宏定义带参数的宏定义可以用不同的参数引用宏

10、PRINTSTAR,得到数目不同的星号输出,例如:善于利用宏定义,可以实现程序的简化。PRINTSTARPRINTSTAR(5 5)/宏替换为一段程序代码/宏替换为一段程序代码PRINTSTARPRINTSTAR(8 8)/宏替换为一段程序代码/宏替换为一段程序代码PRINTSTARPRINTSTAR(1010)/宏替换为一段程序代码/宏替换为一段程序代码21215.1.2 5.1.2 带参数的宏定义带参数的宏定义带参数的宏定义的引用与函数调用在语法上比较相似,例如在调用函数时在函数名后的括号内写实参,要求实参与形参的顺序对应和数目相等。但它们基本含义不同,主要区别是:(1)函数调用时会先计算

11、实参表达式的值,然后参数值传递给形参,程序指令会转到函数内部开始执行。而带参数的宏定义只是参数文本替换,不存在计算实参、参数传递、跳转执行等。22225.1.2 5.1.2 带参数的宏定义带参数的宏定义(2)函数调用是在程序运行时执行的,它会为形式参数分配临时的内存单元。而宏在预处理阶段替换,不会为形式参数分配内存单元,而且也没有返回和返回值的概念。(3)函数调用对实参和形参都要定义类型,且要求二者的类型一致,如果不一致,会进行类型转换。而宏定义不存在类型问题,它的形式参数和引用参数都只是一个文本记号,宏替换时进行文本置换。23235.1.2 5.1.2 带参数的宏定义带参数的宏定义(4)无参

12、数函数调用必须包含括号,无参数宏定义引用时不需要括号。例如:#define PI 3.1415926#define PI 3.1415926/宏定义/宏定义intint funfun();();/函数原型/函数原型x x=funfun();();/函数调用/函数调用x x=PIPI;/宏引用/宏引用24245.1.2 5.1.2 带参数的宏定义带参数的宏定义(5)每一次宏引用,宏替换后都会使源程序增长,相当于将宏定义的字符文本“粘贴”到源程序中一次,而函数调用代码是复用的。宏替换会占用编译时间,函数调用则会占用运行时间。25255.1.2 5.1.2 带参数的宏定义带参数的宏定义(6)宏定义与

13、前面讲的内联函数非常相似。两者区别在于:宏是由预处理器对宏进行替换,它是在代码处不加任何检验的简单替换;而内联函数是通过编译器来实现的,它有函数的特性,只是在需要用到的时候,内联函数像宏一样地展开,取消了函数的参数入栈,减少了调用的开销。内联函数要做参数类型检查,这是内联函数跟宏相比的优势。26265.1.2 5.1.2 带参数的宏定义带参数的宏定义【例5.2】宏引用和函数调用的区别。27275.1.2 5.1.2 带参数的宏定义带参数的宏定义例5.21#include#include 2 intint M1M1(intint y y)3 4 returnreturn(y y)*()*(y y

14、););5 6#define M2(y)(y)*(y)#define M2(y)(y)*(y)7 intint mainmain()()8 9 intint i i,j j;10 forfor(i i=1 1,j j=1 1;i i=5 5;i i+)+)printfprintf(%d,(%d,M1M1(j j+);+);/函数调用处理/函数调用处理11 printfprintf(nn););12 forfor(i i=1 1,j j=1 1;i i=5 5;i i+)+)printfprintf(%d,(%d,M2M2(j j+);+);/宏引用处理/宏引用处理13 printfprintf

15、(nn););14 returnreturn 0 0;15 28285.1.2 5.1.2 带参数的宏定义带参数的宏定义例5.21#include#include 2 int M1(int y)int M1(int y)3 4 return(y)*(y);return(y)*(y);5 6#define M2(y)(y)*(y)#define M2(y)(y)*(y)7 int main()int main()8 9 int i,j;int i,j;10 for(i=1,j=1;i=5;i+)printf(%d,M1(j+);/函数调用处理for(i=1,j=1;i=5;i+)printf(%

16、d,M1(j+);/函数调用处理11 printf(n);printf(n);12 for(i=1,j=1;i=5;i+)printf(%d,M2(j+);/宏引用处理for(i=1,j=1;i=5;i+)printf(%d,M2(j+);/宏引用处理13 printf(n);printf(n);14 return 0;return 0;15 1 4 9 16 251 9 25 49 8129295.1.2 5.1.2 带参数的宏定义带参数的宏定义例5.21#include#include 2 intint M1M1(intint y y)3 4 returnreturn(y y)*()*(y

17、 y););5 6#define M2(y)(y)*(y)#define M2(y)(y)*(y)可以看出函数调用和宏引用在形式上相似,在本质上是完全不同的。30305.1.3#5.1.3#和和#预处理运算预处理运算C语言标准为预处理命令定义了两个运算符:#和#,它们在预处理时被执行。31315.1.3#5.1.3#和和#预处理运算预处理运算#运算符的作用是文本参数“字符串化”,即出现在宏定义字符文本中的#把跟在后面的参数转换成一个C语言字符串常量。例如:#define PRINT_MSG1(x)printf(#x);#define PRINT_MSG2(x)printf(x);#define

18、 PRINT_MSG1(x)printf(#x);#define PRINT_MSG2(x)printf(x);PRINT_MSG1PRINT_MSG1(Hello WorldHello World););/正确,宏替换为 printf(Hello World);/正确,宏替换为 printf(Hello World);PRINT_MSG1PRINT_MSG1(Hello World);(Hello World);/正确,宏替换为 printf(Hello World);/正确,宏替换为 printf(Hello World);PRINT_MSG2PRINT_MSG2(Hello WorldH

19、ello World););/错误,宏替换为 printf(Hello World);/错误,宏替换为 printf(Hello World);PRINT_MSG2PRINT_MSG2(Hello World);(Hello World);/正确,宏替换为 printf(Hello World);/正确,宏替换为 printf(Hello World);32325.1.3#5.1.3#和和#预处理运算预处理运算简单来说,#参数的作用就是对这个参数替换后,再加双引号括起来,变为“参数”。33335.1.3#5.1.3#和和#预处理运算预处理运算#运算符的作用是将两个字符文本连接成一个字符文本,如

20、果其中一个字符文本是宏定义的参数,连接会在参数替换后发生。例如:A字符与#arg参数连接在一起形成了A1,而对于Aarg字符文本,不会进行arg替换。#define SET1(arg)A#arg=arg;#define SET2(arg)Aarg=arg;#define SET1(arg)A#arg=arg;#define SET2(arg)Aarg=arg;SET1SET1(1 1););/宏替换为 A1=1;/宏替换为 A1=1;SET2SET2(1 1););/宏替换为 Aarg=1;/宏替换为 Aarg=1;34345.1.4 5.1.4 预定义宏预定义宏C语言标准中预先定义了一些有用

21、的符号常量,这些符号常量主要是编译信息。35355.1.4 5.1.4 预定义宏预定义宏表5-1 标准预定义符号常量ANSI C标志,若为1说明此程序兼容ANSI C标准int型常量_STDC_当前源代码的行号int型常量_LINE_编译程序文件名字符串常量_FILE_编译程序时间(形式为“hh:mm:ss”,例如“10:20:05”)字符串常量_TIME_编译程序日期(形式为“MM DD YYYY”,例如“May 4 2006”)字符串常量_DATE_说明类型符号常量其中“_”为两个下划线,_DATE_和_TIME_用于指明程序编译的时间,_FILE_和_LINE_用于调试目的,_STDC_检测编译系统是否支持C语言标准。36365.1.4 5.1.4 预定义宏预定义宏例5.511#include#include 2 intint mainmain()()3 4 printfprintf(%s,%s,%s,%d(%s,%s,%s,%dnn,_DATE_DATE_,_TIME_TIME_,_FILE_FILE_,_LINE_LINE_););5 returnreturn 0 0;6 某次运行结果为:Oct 12 2010,21:49:41,D:DEVSHOPCH0551.c,4结束结束

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 大学资料

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com