版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
9.1学习目标通过前面内容的学习可以了解到,利用C语言进行软件开发应遵从模块化设计思想。因此,绝大多数的C语言程序是由一个主函数和若干个自定义函数组成,从而实现功能的模块化。那么,C语言如何实现库函数的引用呢?这就需要了解曾经使用过的#include命令,它是C语言开发系统的“编译预处理命令”。编译预处理是在正式编译开始之前要做的工作。编译预处理命令不是C语言的语句,行尾不允许使用分号。凡是由#开始的命令都是编译预处理命令,尽管编译预处理命令有许多种,但却有着相同的应用规则。那么,究竟C语言提供了哪些编译预处理命令呢?它们都有什么样的特点呢?这就是本章将要学习的内容。返回9.2文件包含文件包含的一般格式为:#include
<文件名>或者:#include
"文件名"命令:include功能:把指定包含的文件插入该命令行位置来取代该命令行,从而把指定包含的文件和当前的源程序文件连成一个源文件。说明:文件包含编译预处理命令必须以符号#开始。下一页返回9.2文件包含文件:多数是头文件,以.h为扩展名。一般有两类,一类是C语言开发系统提供的,存放于系统安装文件夹下的include子文件夹中;另一类是由用户编写的自定义函数。头文件中包含许多函数的定义和宏定义,开发系统将其提供的大量函数分门别类地存放于不同的头文件中。用户也可以将自己经常使用的,但开发系统未提供的函数编写好后存入自己定义的头文件中。读者可以参阅附录四的内容。该命令一般放置在程序的最前端,一条命令只能包含一个文件,若要包含多个文件,必须用多个#include命令,且必须一行一条,行尾不允许有分号。命令与头文件之间习惯上至少设置一个空格,不设置也没错。头文件的界定符号<>和""在预处理时存在的区别如下。上一页下一页返回9.2文件包含另外,include命令的包含对象可以是任意扩展名的文本文件,因此,其应用非常灵活,但并不常用。include命令并非仅对包含文件中有用的信息进行引用,其实质是一种“嵌入”方式,是将被包含文件“嵌入”到当前文件中,读者可参阅“精选案例”。在“工资管理系统”的源代码中,文件包含命令为:#include<stdio.h> /*基本输入/输出函数包含在此*/#include<conio.h> /*getch()及getche()函数包含在此*/#include<string.h> /*字符串相关函数包含在此*/#include"windows.h" /*Sleep()函数包含在此*/上一页返回9.3宏
定
义在前面章节中,还用过#define命令,这也是一条编译预处理命令,称为“宏定义”。其一般格式为:#define<标识符>[字符串]命令:define功能:用一个标识符来表示一个字符串。说明:宏定义编译预处理命令必须以符号#开始。标识符:由用户按照标识符的命名规则命名,对英文字母大小写无要求,习惯上全部用大写字母。“宏定义”命令与标识符、标识符与字符串之间至少需要一个空格,字符串内的空格作为字符串的一部分;另外,宏定义可以带参数。因此,有不带参数的宏定义和带参数的宏定义两种。下一页返回9.3宏
定
义9.3.1.不带参数的宏定义例如:#definePI3.1415926#defineSTUstructstu该预处理命令的主要作用是:在进行正式编译源程序之前,将源程序中所有除字符串常量中的PI之外的标识符替换为3.1415926。因此,也称这种不带参数的宏定义为“宏替换”,这个预处理中替换的过程称为“宏展开”。不带参数的宏定义的特点如下。①可以将一个相对较长的字符序列用较短的标识符进行替换。②当源程序中大量出现相同的字符序列时,采用宏替换可以降低输入代码的失误率、提高输入效率、增加程序的可读性。上一页下一页返回9.3宏
定
义③为提高程序调试效率,也往往采用宏替换命令。如:在调试循环结构时,如果循环次数很多,运算量很大,需要很长时间时,可以采用宏定义表示循环边界。④宏定义中的字符串应该理解为“字符序列”,一般不带双引号;否则双引号被视为“字符序列”的一部分,注意与字符串常量中双引号的区别。另外,除非有特殊需要,末尾也不加分号,否则也视为“字符序列”的一部分。⑤在同一作用域中定义的宏名,在宏展开时,若包含已经定义过的宏名,将被已经定义过的宏名中的字符串替换。上一页下一页返回9.3宏
定
义【案例9-1】不带参数的宏定义的应用。〖分析〗①宏定义一个符号常量。②宏定义一个字符串。③宏定义一个含有C语言转义字符的字符串。④宏定义一条C语言语句。〖代码〗#include<stdio.h>#include<string.h>上一页下一页返回9.3宏
定
义#defineZP45 /*宏定义一个字符常量ZP,代表45*/#defineHRY"WelcometoHandan!" /*宏定义一个C语言的字符串*/#defineHDYD"Howoldareyou?\n" /*宏定义字符序列可以有“\”字符,替换后形成转义符号*/#definePRINTprintf("IloveHandan.\n"); /*宏定义字符序列中含有引号*/main(){ charstr[]=HRY;
printf("ZP+36=%d\n",ZP+36); printf("string1=%s\n",str);上一页下一页返回9.3宏
定
义printf("string2=%s\n",HDYD); PRINT}程序运行结果如图9-1所示。上一页下一页返回9.3宏
定
义【案例9-2】同一作用域中宏名的替换。〖分析〗①为计算45+36的和,分别定义3个字符常量:L代表45、B代表36、S代表L+B。②为输出WelcometoHandan!,亦定义3个宏名,分别代表3个单词。在宏定义的字符序列中,如果涉及字符串与其他宏名形成新字符串时,其格式为:宏名"字符序列"或宏名
"字符序列"。〖代码〗#include<stdio.h>
#defineL45#defineB36#defineSL+B /*此处的L和B将在预处理时被上两行定义的宏名进行替换*/上一页下一页返回9.3宏
定
义#defineW"Welcome" /*宏定义W代表Welcome*/#defineTW"to" /*W与to之间的空格可以不要*/#defineHT"Handan!”
main(){ printf("%d\n",S); printf("%s\n",H);}程序运行结果如图9-2所示。上一页下一页返回9.3宏
定
义9.3.2.带参数的宏定义其一般格式为:#define<标识符(参数表)><字符串>命令:define说明:“标识符(参数表)”中的小括号不能省略,且与标识符之间不能有空格存在。标识符:由用户按照标识符的命名规则命名,英文字母大小写无要求,习惯上用大写英文字母。字符串:包含括号中指定的参数,否则参数表失去作用。在宏定义时,宏名可以带有参数。在进行宏展开时,每当遇到该宏名时,与其有关的参数即用程序中的实际参数所替换。这种带参数的宏定义经常用于简化源程序中的表达式。上一页下一页返回9.3宏
定
义【案例9-3】利用带有一个参数的宏定义,计算圆面积。〖分析〗①在圆面积的计算中,半径的不同决定了圆面积的不同,因此,将半径r确定为宏定义的可变参数。②当为r赋值为1.2和2.6时,计算圆面积并输出结果。〖代码〗#include<stdio.h>
#definePI3.1415926#defineS(r)PI*r*r /*带参数的宏定义,习惯上参数用小写字母*/上一页下一页返回9.3宏
定
义main(){ floatr; r=1.2; printf("r=%f\tArea=%f\n",r,S(r)); r=2.6; printf("r=%f\tArea=%f\n",r,S(r));}程序运行结果如图9-3所示。〖说明〗输出语句在预处理时,被宏展开为“printf("r=%f\tArea=%f\n",r,3.1415926*r*r);”之后,编译系统才对源程序进行编译。上一页下一页返回9.3宏
定
义【案例9-4】利用带有两个参数的宏定义,计算矩形面积。〖分析〗①在矩形面积的计算中,长与宽的变化影响着矩形的面积。因此,将矩形的长length与宽width确定为宏定义的参数。
②当为length和width分别赋值为4和3、45和36时,计算矩形的面积并输出结果。〖代码〗#include<stdio.h>
#defineS(a,b)a*bmain(){ floatlength=4,width=3;上一页下一页返回9.3宏
定
义printf(“length=%5.2f\twidth=%5.2f\tArea=%7.2f\n”,length,width,S(length,width)); length=45,width=36; printf(“length=%5.2f\twidth=%5.2f\tArea=%7.2f\n”,length,width,S(length,width));}程序运行结果如图9-4所示。上一页下一页返回9.3宏
定
义〖说明〗输出语句在预处理时,被宏展开为“printf(“length=%5.2f\twidth=%5.2f\tArea=%7.2f\n”,length,width,length*width);”之后,编译系统才对源程序进行编译。通过以上两个案例可知,带参数的宏定义也是在宏展开的过程中进行宏替换。但有了参数的存在,读者在应用时一定要注意宏展开后程序代码功能的正确性,如【案例9-5】所示。【案例9-5】使用带有一个参数的宏定义,计算圆面积。〖分析〗当为r赋值为1.2时调用S(r)和调用S(0.6+0.6),分别计算圆面积并输出结果。上一页下一页返回9.3宏
定
义〖代码〗#include<stdio.h>
#definePI3.1415926#defineS(r)PI*r*rmain(){ floatr=1.2; printf(“r=%f\tArea=%f\n”,r,S(r)); printf(“r=%f\tArea=%f\n”,r,S(0.6+0.6));}上一页下一页返回9.3宏
定
义程序运行结果如图9-5所示。在半径r同为1.2时,为什么会出现不同的结果呢?〖说明〗①第一条输出语句在预处理时,被宏展开为如下内容。printf(“r=%f\tArea=%f\n”,r,3.1415926*r*r);②第一条输出语句在预处理时,被宏展开为如下内容。printf(“r=%f\tArea=%f\n”,r,3.1415926*0.6+0.6*1.6+0.6);③如果希望S(0.6+0.6)在宏展开之后,不会影响程序的正确性,应该定义为:#defineS(r)PI*(r)*(r)上一页下一页返回9.3宏
定
义读者可以自行测试。通过【案例9-5】可知,在应用带参数的宏的时候,宏定义字符串时可以使用括号,在某些情况下甚至是必须使用括号才能保证程序的正确性。初学者在学习自定义带参数的函数和带参数的宏时,容易将两者混淆,下面对带参数的宏定义和带参数的函数之间的区别加以分析。①书写格式不同:带参的宏必须以#define开始,行尾无分号;函数声明语句行尾有分号;宏定义的位置一般在预处理命令之后、main()函数之前;函数定义位置通常在main()之后。②参数要求不同:带参的宏中的参数无数据类型要求,而函数的形参则要求定义类型。上一页下一页返回9.3宏
定
义③作用时间不同:带参的宏是编译预处理命令,是在编译之前进行的宏展开,而函数是在程序编译成功,并链接成可执行文件后,在程序运行期间被调用后才起作用。④工作原理不同:带参的宏中的参数如果是表达式,在预处理阶段仅实现宏展开工作,并不对展开的表达式进行运算,宏展开不占用最终程序的运行时间,而仅占用预处理或编译时间。而函数在调用时,如果参数是表达式,则先进行计算再进行传递,调用函数时占用程序运行时间。上一页返回9.4条件编译9.4.1.#ifdef…#else…#endif#ifdef标识符
程序块1#else
程序块2#endif这一组命令所实现的功能是:如果标识符已用#define命令定义过,则编译程序块1,否则编译程序块2。下一页返回9.4条件编译可以没有#else程序块2,即:#ifdef标识符
程序块#endif如果标识符已被#define命令定义过,则编译程序块,否则该程序块不被编译。上一页下一页返回9.4条件编译9..4.2.#ifndef…#else…#endif#ifndef标识符
程序块1#else
程序块2#endif与第一种格式类似,只是将#ifdef改为#ifndef,预处理时正好相反,如果标识符未曾被#define定义,则编译程序块1,否则编译程序块2。也可以没有#else程序块2。上一页下一页返回9.4条件编译9..4.3.#if…#else…#endif#if常量表达式
程序块1#else
程序块2#endif此预处理命令的功能是:如果常量表达式为真,则编译程序块1,否则编译程序块2,同样允许无#else程序块2。形式上看以上3种条件编译命令与C语言if-else语句非常相似,其工作原理也比较相像,但本质是有区别的:条件编译命令使得源程序在编译时,并非全部代码都被编译,而是有选择地进行编译。选择语句if-else中所有代码都将被编译,其在运行时才进行选择。上一页下一页返回9.4条件编译【案例9-6】条件编译。根据标识符FLAG是否定义,决定编译源程序中哪条输出语句,从而输出WelcometoHandan!,或输出IloveHandan.。〖代码〗#include<stdio.h>#defineFLAGset
main(){#ifdefFLAG /*判断FLAG是否曾被#define*/ printf(“WelcometoHandan!\n”);#else printf(“IloveHandan!\n”);上一页下一页返回9.4条件编译#endif}程序运行结果如图9-6所示。〖说明〗①由于FLAG在程序前部进行了定义:“#defineFLAGset”,所以,源程序在预处理后,只将第一条输出语句进行编译,而放弃编译第二条语句。②FLAG在宏定义时指定了字符串set,set本身对本程序的预处理没有起作用。实质上,即使在宏定义FLAG时不指定字符串,结果也是一样的,可以理解为FLAG被定义为空,但事实上是已经定义了。③如果将“#defineFLAGset”从程序中删除或注释掉,编译程序将放弃第一条输出语句,而仅对第二条输出语句进行编译,程序运行后将输出“IloveHandan”.。上一页下一页返回9.4条件编译【案例9-7】条件编译。根据常量表达式的值,决定编译源程序的哪条输出语句,从而输出Howareyou?,或输出Howdoyoudo?。〖代码〗#include<stdio.h>main(){#if5+6-11 printf(“Howareyou?\n”);#else printf(“Howdoyoudo?\n”);#endif}程序运行结果如图9-7所示。上一页返回9.5知识扩展在工业控制领域的应用软件的开发中,将会大量使用#define,例如对单片机端口等进行宏定义。开发人员会选择将大量的宏定义保存在某个头文件中,并将其包含在当前程序中,从而使源程序代码可读性提高,程序也显得简练。如以下“串行驱动LED显示”的头文件中,定义了一系列的宏。/*宏定义*/
#definenul0xf#defineqc0xc……下一页返回9.5知识扩展#defineqj0x12#defineqn0x13……#defineqlf0x22#defineqlg0x23#defineqldp0x24上一页返回9.6精选案例【案例9-8】在C:盘根文件夹下创建一个a.c文件,内容如下。voidprint(){ printf(“WelcometoHandan!\n”);}创建一个C语言源程序9-8.c,将文件a.c包含进来,编译链接后运行程序并输出结果。〖分析〗①预处理命令的文件包含命令中的文件名支持路径表达,命令应为:#include“c:\a.c”。②为说明问题,main()函数仅调用print()。下一页返回9.6精选案例〖代码〗#include<stdio.h>#include“c:\a.c”main(){ print();}程序运行结果如图9-8所示。上一页下一页返回9.6精选案例〖说明〗①#include命令中的文件可以是任意扩展名的文件,只要其内容是文本,且符合C语言规则,并与当前源程序能够共同完成某种功能即可。②将命令#include的作用理解为将某个文件“嵌入”到当前文件更加准确,如果将命令行#include“c:\a.c”移到print()之后的任何位置,将无法通过编译。这是因为预处理后的print()定义的位置在其被引用之后。当然,认为#include命令存在作用域,也是正确的。【案例9-9】学生食堂套餐。输入拼音缩写,输出客人所点套餐名称,提供4元套餐、5元套餐、9元套餐。〖分析〗①宏定义3种套餐的标识符,标识符由3种套餐的拼音缩写构成。②定义一个字符数组,用于接收用户所点套餐的拼音缩写。③判断用户输入字符串,输出相应套餐名称。上一页下一页返回9.6精选案例〖代码〗#include<stdio.h>#include“string.h”
#definesytc“4元套餐”#definewytc“5元套餐”#definejytc“9元套餐”上一页下一页返回9.6精选案例main(){ charstr[30]; printf(“售饭窗口:\n\t您要什么套餐?”); scanf(“%s”,str); if(!strcmp(str,”sytc”)) printf(“\t好嘞,%s一份!\n”,sytc); elseif(!strcmp(str,”wytc”)) printf(“\t好嘞,%s一份!\n”,wytc); elseif(!strcmp(str,”jytc”)) printf(“\t好嘞,%s一份!\n”,jytc); elseprintf(“\t对不起,我们没有!\n”);}程序运行结果如图9-9所示。
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 武术教学场域下学生成就目标定向的多维解析与影响因素探究
- 次贷危机背景下中国资产证券化的挑战、机遇与发展路径探究
- 子宫复旧不全的护理
- 河南省湘豫联盟2025-2026学年高三下学期四月阶段检测地理+答案
- 重庆市2026年普通高等学校招生全国统一考试高三第二次联合诊断考试数学+答案
- 税务申报与处理方法手册
- 健康险产品责任履行承诺函6篇范文
- 无人机操作与维护手册指南
- 员工加班申请审批指引说明(6篇)
- 客服客户问题快速解决SOP手册
- 《财经应用文写作》课件-第八章 经济评论
- 售后服务管理师培训课件
- 小学一年级语文学习评价方案设计
- 本工程施工的重点难点及应对措施
- 绿化保洁安全培训课件
- 知道智慧树系统思维与系统决策满分测试答案
- 养老险产品销售话术培训方案
- 采血飞针技术培训课件
- 2025年中国糖尿病肾脏病基层管理指南(全文)
- 2025年新疆高端会计人才笔试题及答案
- 物流运输货物损坏免责合同
评论
0/150
提交评论