




已阅读5页,还剩56页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第12章C语言的预处理器,12.1宏定义和宏替换12.2文件包含12.3条件编译,编译预处理命令不是C语言的语句,它的作用只是告诉(命令)编译系统,在编译源程序之前对源程序进行某种预加工,而后再进行编译。所有的编译预处理命令都是以符号“#”开头,末尾不加分号。预处理命令可以用在程序的任何地方。本章主要介绍以下的语言的编译预处理命令:,宏定义的命令:#define,#undef;文件包含命令:#include;条件编译命令:#if_#else_#endif;#if_#elif_#endif;#ifdef_#else_#endif;#ifndef_#else_#endif。,12.1宏定义和宏替换,12.1.1不带参数的宏定义和引用不带参数的宏定义的一般形式为:#define宏名字符序列宏定义的作用是,在对源程序编译之前,将程序中出现的所有的宏名用对应的字符序列来代替。这种替换称宏替换或宏引用。,不带参数宏替换,通常的用途是,用宏名定义程序中的常量,如:#defineFALSE0#defineWORDSTurboC+通常把宏定义写在文件的开始部分,函数的外面,或写在包含文件(#include)中。,例12.1.1宏定义与宏替换应用。程序定义了一个宏名:SIZE,用来定义数组str的容量。程序中还使用了系统定义的一个宏名NULL(空字符),用于检查字符型数组中字符串的结束符。程序的功能是,将用户输入的字符串存入数组str,然后,变成大写字母将其输出。程序如下:,#includestdio.h#defineSIZE80/*宏定义SIZE*/main()inti;charstrSIZE;/*宏SIZE的引用*/printf(Enterastring:);gets(str);,for(i=0;stri!=NULL;i+)/*宏NULL的引用*/printf(%c,toupper(stri);printf(n);return;,宏替换的另一个常见的应用,是语句串的替换。也就是用一个宏名代表一组C语句。编译时,凡是程序中遇到这个宏名,就用这些语句代替。这相当于调用无参数的函数。例12.1.2求1num之间的质数的程序。程序中使用了如下的C语句宏定义:#definePRIMEfor(i=2;i(b)?(a):(b)/*宏定义*/main()inta,b,max;printf(Enter2numbers:);scanf(%d%d,max=MAX(a,b);/*宏替换*/printf(Themanximumnum=%dn,max);return0;也可以将程序中的两个语句:max=MAX(a,b);printf(Themanximumnum=%d,max);,写成如下的一个语句:printf(Themanximumnum=%d,MAX(a,b);其效果是一样的。我们看到,这种宏替换很象调用函数。例如:max=MAX(a,b);MAX(a,b);,但它们的工作的机理是完全不同的,在概念更上不要混淆。它们之间的不同,体现在以下四个方面。(1)函数调用时,要计算实参并向形参传送。而宏中的参数,只是进行简单的替换。既没有向形参拷贝数据,也没有传送参数地址。,(2)函数中的实参和形参有确定数据类型,并且两者是一一对应的。宏名没有数据类型。它只是个符号。其参数也只是个符号而已。引用时,代入指定的字符。宏定义的字符串可以是任何数据类型。(3)宏是在编译时进行替换的,不分配内存空间。而函数调用是在程序运行时处理的,并分配相应的临时的内存空间。,(4)宏替换是不占程序的运行时间的,只占编译时间。但宏替换增加程序代码长度。宏替换的次数越多,程序代码长度越长。函数调用要消耗程序的运行时间,但不使程序变长。灵活恰当地运用宏替换,可以使源程序显得简洁,增加源程序的可读性。,例12.1.6编写程序,将例12.1.3中无参数宏定义改为带参数r的宏定义:#defineS(r)PI*(r)*(r)#defineL(r)2*S(r)/(r)程序如下:,#includestdio.h#definePI3.14159/*定义不带参数的宏*/#defineS(r)PI*(r)*(r)/*定义带参数r的宏*/#defineL(r)2*S(r)/(r)/*定义带参数r的宏*/main(),floatr;printf(Enterr:);scanf(%f,在以上两个例子中,宏的形参都用圆括号括起来了。这不是绝对必要的。例如,例12.1.5中宏定义也可以写成下面的形式:#definePI3.14159#defineS(r)PI*r*r#defineL(r)2*S(r)/r,但是,对于实参为表达式的情况,上面参数不带括号宏定义,可能会给出错误的计算结果。设有r=3.0.a=1.0.b=2.0根据上面的宏定义,则有:S(r)=s(3)=28.27431,L(r)=l(3)18.84954而参数为表达式时,S(a+b)=S(3)=7.14159,L(a+b)=12.28318,显然结果是错的。后者因为实参没有括号,所以计算过程是:S(a+b)=3.141591+21+2=3.14159+2+2=7.14159如果在宏定义里给参数r加上括号,则计算过程是:S(a+b)=3.14159(1+2)(1+2)=3.1415933=28.27431结果是正确的。,为了避免出现上述可能出现的错误,在定义带参数的宏时,最好给参数加上圆括号。,12.1.3取消宏定义#undef命令用于取消先前已定义的宏名。其一般形式为:#undef宏名,12.2文件包含,所谓文件包含,是指一个源文件将另一个源文件包含到自己的文件之中。文件包含命令有如下两种形式:#include#include文件名包含命令的功能是,在编译预处理时,用命令指定的文件名的文本内容来替代该命令,使包含文件的内容成为本程序的一部分。,如果文件名用了双引号,则首先查找当前目录,若找不到该文件,则查找命令行定义的其他目录。如果仍找不到该文件,则查找系统定义的标准目录。如果文件名使用了尖括号,则编译器首先查找命令行指定的目录;如果找不到该文件,则查找标准目录,不查找当前工作目录。,例12.2.1给定半径,计算圆的周长和圆面积。为了展示利用文件包含命令处理多文件程序的设计方法,我们设计三个如下的包含文件,或称头文件:头文件1名为myin1.h。文件内容包含如下两条:#include#definePI3.14159/*宏定义PI*/,头文件2名为myin2.h。其内容是函数lr的定义:floatlr(floatr)/*计算圆周长的函数*/return2*sr(r)/r;头文件3名为myin3.h。文件内容是函数sr的定义。,floatsr(floatr)/*计算圆面积的函数*/returnPI*r*r;设计一个含有上述三个头文件和主函数程序如下:#includemyin1.h#includemyin3.h,#includemyin2.hmain()floatx=3.0;printf(L=%fn,lr(x);printf(S=%fn,sr(x);,这里在文件myin3.h和文件myin2.h中定义的两个函数是嵌套的。即函数lr()的定义中引用着函数sr()。函数sr()定义中还引用着头文件myin1.h中的宏定义PI。因此,在主函数文件中,三个包含命令的文件书写顺序,必须是先myin1.h,然后myin3.h,最后是myin2.h。,使用包含文件的结果,本例的源程序由四个文件组成:三个头文件和一个主程序文件。经过编译预处理后,三个头文件被“包含”到主程序文件中,成为程序的组成部分。图12.1给出本例包含文件处理的情形。,图12.1例12.2.1包含文件处理示意图,12.3条件编译,C语言的条件编译预处理命令就是用于有选择的编译源程序中某些部分的。条件编译主要用于调试程序。条件编译的另一个用途是,可以用源程序产生不同版本。,12.3.1#if_#endif类型的条件编译命令这是根据表达式的值进行条件编译的命令。该条件编译命令有以下三种不同形式。1#if_#endif此命令的一般形式为:#if常数表达式程序段#endif,其作用是,如果常数表达式为真,则编译从#if到#endif之间的程序段(活语句块);否则就不编译,跳过这段程序。2#if_#else_#endif此命令的一般形式为:#if常量表达式程序段1#else程序段2#endif,其作用是,如果常量表达式为真,编译程序段1的代码段;否则,编译程序段2的代码段。例12.3.1用户给定一整数MAX。当MAX大于或等于100时,编译语句:printf(MAX=100);否则,编译语句:printf(MAX=100printf(MAX=100n);,#elseprintf(MAX100n);#endifprintf(MAX=%dn,MAX);return0;,3#if_#elif_#endif这是用于多路选择的编译命令。它的一般形式为:#if常量表达式1程序段1#elif常量表达式2程序段2,#elif常量表达式n程序段n#endif其作用是,如果常量表达式1为真,则编译程序段1;否则,如果常量表达式2为真,则编译程序段2;否则,如果常量表达式3为真,则编译程序段3;直到最后,如果常量表达式n为真,则编译程序段n。,12.3.2#ifdef和#ifndef类型的条件编译命令这是根据标识符的定义与否进行条件编译的命令。标识符是用宏定义命令实现的。因此,也可以说,这种条件编译是根据宏名是否被定义决定某程序段是否进行编译。这种条件编译预处理命令有两种格式。,1#ifdef_#endif类型条件编译命令这种类型的命令有以下两种格式:第一种格式为:#ifdef宏名程序段#endif,它的作用是,如果宏名在此前的#define中已经定义,则编译#ifdef后边的程序段(语句块)。否则不编译,跳过此程序段。第二种格式为:#ifdef宏名程序段1#else程序段2#endif,它的作用是,如果宏名在此前的#define中已经定义,则编译程序段1;否则编译程序段2。例12.3.2应用#ifdef条件编译命令的简单演示。#include#defineVALUE1main(),#ifdefVALUEprintf(VALUEisdefined.);printf(VALUE=%dn,VALUE);#elseprintf(VALUEisnotdefined.);#endifret
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 物理-福建省莆田市2025届高中毕业班第二次教学质量检测试卷(莆田二检)试题和答案
- 历史-陕西省安康市2025届高三下学期第二次质量联考(安康二模)试题和答案
- 除草布施工方案
- 广东省肇庆市2024-2025年高中地理 农业和工业练习评讲教学实录 新人教版必修2
- 个人瓷砖买卖合同范例
- 供货茶叶合同范例
- 关于定金合同范例
- 公司合作加盟合同范例
- 构建班级共同价值观的策略计划
- 学生课外阅读推广活动计划
- 基于实验教学培养学生物理核心素养的研究
- 2023年汉字听写大会汉字听写知识竞赛题库及答案
- 退化林修复投标方案
- 钻孔桩水下混凝土灌注记录(自动生成)1
- 切削刀具及其材料课件
- 穿刺手术导航定位系统(CQZ2201581)
- 小学心理健康教育-想法变一变心情换一换教学课件设计
- 机械加工工艺过程卡片(实例)
- 足球脚内侧传球 课件
- 甲亢的中医辨证施治
- 统编教材二年级下册“写话”编排特色解析
评论
0/150
提交评论