C第11章教学zp.docx
《C第11章教学zp.docx》由会员分享,可在线阅读,更多相关《C第11章教学zp.docx(6页珍藏版)》请在冰豆网上搜索。
![C第11章教学zp.docx](https://file1.bdocx.com/fileroot1/2023-1/31/8784ac10-004b-4899-87df-6f45351fc6d5/8784ac10-004b-4899-87df-6f45351fc6d51.gif)
C第11章教学zp
第十一章编译预处理(P181)
11.1编译预处理
一、宏定义#define
二、带参数的宏定义
三、取消宏定义#undef宏名。
11.2文件包含处理
第十一章编译预处理
11.1编译预处理
C中预处理命令的作用是告诉编译系统在对源程序编译之前应该做什么。
正确地使用编译预处理功能可有效底提高程序的开发效率。
编译预处理命令有三种:
文件包含、宏定义和条件编译。
为了和程序语句区别,编译预处理命令以#号开头(前面没有空格)且占用一个单独的书写行,命令尾不使用分号作为结束符。
一、宏定义#define(P179)
所谓宏定义就是用一些比较容易理解或具有物理意义的符号代替另一些数据或文本,其意义在于:
不仅可提高程序的易读性,还便于程序的维护和修改。
1.不代参数的宏定义
就是用一个指定的标识符(即宏名)来代表一个字符串。
宏定义的一般形式为:
#define标识符字符串
例如:
#defineYES1
#defineNO0
功能是:
将符号常量YES定义为1,NO定义为0,其中,YES和NO称为宏名。
在编译预处理时,编译系统把程序中出现的YES(或NO)一律用1(或0)替换。
if(x==YES)
printf(“correct!
”)
elseif(x==NO)
printf(“error!
”)
在执行编译处理后,即为:
if(x==1)
printf(“correct!
”)
elseif(x==0)
printf(“error!
”)
案例11。
1定义宏表示圆周率常数
#include
#definePI3.14159
voidmain()
{floatc;
c=2*PI*3.0;
printf("c=%f\n",c);
}
案例11。
2定义宏表示代码行
#include
#definePRTprintf("\n");
voidmain()
{printf("*********");
PRT
printf("*********");
}
说明:
(1)宏名习惯上一般用大写字母表示,以区别于变量名;
(2)宏定义是用宏名代替一个字符串,他只是做简单的替换,不做语法检查;
例如:
#definePI3.i4i159
只要当编译系统在编译已被宏代换的源程序时,才会检查出错误。
(3)宏定义不同于C语句,不能在末尾加分号;
(4)在宏定义命令中,可以使用已经定义过的宏名,即宏定义可以层层代换。
案例11。
3分析如下程序结果
#include
#defineA40
#defineB1(A+20)
#defineB2A+20
#defineC1B1*A
#defineC2B2*A
voidmain()
{printf("c1=%d\n",C1);
printf("c2=%d\n",C2);
}
分析:
置换后:
printf(“c1=%d\n”,(40+20)*40);
printf(“c1=%d\n”,40+20*40);
(5)同一宏名不能重复定义;
(6)替换文本不能替换双引号中与宏名相同的字符串;
例如:
printf(“YES”)中的YES。
二、带参数的宏定义P180
带参数的宏定义是更高级的宏定义,不仅要进行字符串替换,同时还要进行参数替换。
一般形式为:
#define宏名(参数表)字符串
例如:
#definePOWER(x)((x)*(x))
其中,POWER是宏名,x是形参。
案例11。
4分析程序
#include
#definePOWER(x)((x)*(x))
voidmain()
{inta=4,b=6,c;
c=POWER(a+b);
printf("c=%d",c);}
分析:
在程序编译时,进行宏展开即为:
c=((a+b)*(a+b))
若定义为:
#definePOWER(x)x*x
则宏展开为:
c=a+b*a+b
*带参数的宏与函数比较
①在使用形式和特性上与函数相似,但本质不同:
②函数的调用是在程序运行时处理的,而宏的代换是在编译之前进行的;
③函数调用时需先求出实参表达式的值,然后代入形参,而使用带参数的宏只是进行简单的字符替换。
例如上例中的POWER(a+b)在替换时并不先求a+b的值,而只是将实参a+b代替形参x;
④函数调用时存在着从实参向形参的传递数据的过程,而带参数的宏不存在这种值的传递,也没有返回值的概念;
⑤函数调用时,对使用的实参有一定的数据类型的限制,即一般要求实参与形参类型一致,而带参数的宏的实参可以是任意类型的数据;
⑥使用函数调用会占用较多的运行时间,而宏替换只占编译时间。
三、取消宏定义#undef宏名。
例如:
#definePI3.14
main()
…
#undefPI
11.2文件包含处理
文件包含处理#include的作用是将已定义好的头文件包含到代码文件中。
编译预处理中的文件包含通常有以下两种形式:
形式一:
#include〈文件名〉
形式二:
#include“文件名”
例如:
#include〈stdio.h〉
文件包含的功能是:
在编译源程序之前,用指定文件中(如stdio.h)的内容取代该预处理命令。
即是从磁盘中读取该文件,然后把他写入源程序中预处理命令#include的位置上,使他成为源程序的一部分,然后和源程序一起作为一个整体进行编译。
说明:
(1)形式一通常用于系统头文件的嵌入,形式二用于用户创建的某个代码文件的嵌入;
(2)通常,在开发较大的C程序时,会将一些常用的宏定义、结构类型定义、函数说明语句等由多个开发员共用的一些信息统统放在一个文件中,该文件的后缀通常为.h(h表示header,用.c也可以),称为标题文件或头文件。
每个程序员都可以用一个#include命令将这个头文件包含在自己的文件加以使用,这样可以提供一种标准化手段,即每个程序员都使用具有相同值的相同定义。
此外使每个程序员节省时间开销,减少错误的发生。
案例11。
5分析如下程序
用户自定义头文件:
format.h
#definePRINTD(d)printf("integerout:
%d\n",d);
#definePRINTF(f)printf("floatout:
%f\n",f);
#definePRINTS(s)printf("stringout:
%s\n",s);
#include
#include
#include"format.h"
关于#include命令的几点说明:
①一个#include命令只能指定一个被包含文件,若要包含多个文件,需多次使用#include命令;
②#include命令可以嵌套使用;
例如:
在程序f1.c中有如下行:
#include“f2.c”
而在文件f2.c中又有如下行:
#include“f3.c”
则等价于在文件f1.c中包含如下行:
#include“f2.c”
#include“f3.c”
注意以上两个命令的顺序。
③#include两种命令的区别在于:
当用“〈〉”包围文件时,其意义是指示编译系统按系统设定的标准方式搜索文件;而用双引号包围文件时,系统先在源文件(如f1.c)所在目录中搜索文件,若找不到,再按系统设定的标准方式搜索其他目录。