(第8章_预处理)解析
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
答案:11 宏只是字符串简单替换,调 用上式时,替换为(2+3*2+3)=11.因此, 计算正方形面积的宏应该写为#define area(a) ((a)*(a))
下面程序的运行结果是() #define M 5 #define N M+1 #define NN N*N-M main() { printf(“%d\n”,3*NN); } A 21 B 16 C 103 D
宏名替换规则示例。 /*源文件名:AL8_3.c*/ #include <stdio.h> #define NUM 100 void main() { printf("NUM"); } 该程序经过编译、连接、运行,屏幕显示: NUM 从例8.3的运行结果可以看出,程序并未对 printf语句中被双引号括起来的NUM进行替 换,而是将“NUM”当作字符串处理。
2019/1/6
(7)可用宏定义表示数据类型,使书写 方便,但在使用时格外小心。
例如: #define PIN int * 对语句: PIN x,y; 进行宏替换后变为: int * x,y; 表示x为整型的指针变量,y为一般的整型变 量,而并非两个都为指针变量。由这个例子 可见,宏定义虽然也可表示数据类型,但毕 竟是作字符代换。在使用时要分外小心,以 免出错。
2019/1/6
2.使用宏定义的优点
(1)可提高源程序的可维护性 (2)可提高源程序的可移植性 (3)减少源程序中重复书写字符串的工 作量
2019/1/6
3.宏替换
编译预处理时,在宏定义命令之后出现的所 有宏名,均被替换成代替字符串。这一过程 称为“宏替换”,又叫做“宏展开”。例8.2 进行宏替换后为: #include <stdio.h> void main() { printf("PI=%f\tR=%f\tS=%f\n", 3.1416,2.0,3.1416*2.0*2.0); } 该程序经过编译、连接、运行,屏幕显示: PI=3.1416 R=2.0 S=12.5664
对上述程序进行宏替换后 ,其main函数相当于 void main() { int a=5, c=8, e=11; float b=3.8, d=9.7, f=21.08; printf("%d\t %.2f\n",a,b); printf("%d\t %.2f\n",c,d); printf("%d\t %.2f\n",e,f); } 程序运行情况如下: 5 3.80 8 9.70 11 21.08
108
答案:B 3*NN=3*N*N-M=3*M+1*M+1M=3*M+1=3*5+1=16
8.3 文件包含
文件包含是指一个源文件可以将另一个源 文件的全部内容包含进来。前面用此命令 曾多次包含过库函数的头文件。例如: #include <stdio.h> #include "math.h "
1.无参宏定义 无参宏定义的格式: #define 标识符 字符串 C语言中,以“#”开头表示这是一条预处理 命令。“define”为宏定义命令。“标识符” 为所定义的宏名。“字符串”可以是常数、 表达式、格式串等。
2019/1/6
例8.2
无参宏定义示例
#include <stdio.h> #define PI 3.1416 #define R 2.0 #define S PI*R*R #define PRN printf #define BEGIN main(){ #define END } BEGIN PRN("PI=%f\tR=%f\tS=%f\n", PI,R,S); END
2019/1/6
例如:
#define PI 3.14159 void main() { …… } #undef PI f1() { …… } 表示PI只在main函数中有效,在函数f1中无效。
2019/1/6
(5)对双引号括起来的字符串内的字符 ,即使与宏名同名,也不进行宏替换。
2019/1/6
1.文件包含命令的两种格式
#include “包含文件名” #include <包含文件名> 文件包含命令的作用是将指定的文件包含到本文 件中该命令行所在的位置,用被包含源文件中的 全部内容代替该命令行。该命令两种格式的区别 : (1)双引号格式:系统首先到当前目录下查找被 包含文件,如果没找到,再到系统指定的“包含文 件目录”(由用户在配置环境时设置)去查找。 (2)尖括号格式:直接到系统指定的“包含文件 目录”去查找。 一般来说,使用双引号比较保险。
请输入三个数,数之间用空格隔开: 5.2、4.8、7.9↙ 最大数为:7.900000
2019/1/6
8.2 宏定义
C语言提供了多种预处理功能,如宏
定义、文件包含、条件编译等。合理 地使用预处理功能会使编写的程序更 便于阅读、修改、移植和调试,也有 利于模块化程序设计。
2019/1/6
8.2.1 无参宏定义和宏替换
C 语言程序设计
第8章 编译预处理
大连理工大学出版社
第8章 编译预处理
8.1 预处理引例 8.2 宏定义 8.3 文件包含 8.4 条件编译 本章小节
2019/1/6
8.1 预处理引例
ห้องสมุดไป่ตู้
例8.1使用带参宏,实现求三个数中的最大数并输出。 /* 源文件名:AL8_1.c */ #include <stdio.h> #define MAX(a,b) (a>b)?a:b void main() { float num1,num2,num3,max; printf("请输入三个数,数之间用空格隔开:\n"); scanf("%f%f%f",&num1,&num2,&num3); max = MAX(num1,num2); max = MAX(max,num3); printf("最大数为:%f",max); } 程序运行情况如下:
2019/1/6
(3)使用有参函数,无论调用多少次,都不会使 目标程序变长,但每次调用都要占用系统时间进 行调用现场保护和现场恢复;而使用有参宏,由 于宏展开是在编译时进行的,所以不占运行时间 ,但是每引用1次,都会使目标程序增大1次。 (4)在带参宏定义中,形式参数不分配内存单元 ,因此不必作类型定义。而宏调用中的实参有具 体的值。要用它们去代换形参,因此必须作类型 说明。这是与函数中的情况不同的。在函数中, 形参和实参是两个不同的量,各有自己的作用域 ,调用时要进行“值传递”。而在带参宏调用中 ,只是符号代换,不存在值传递的问题。
2019/1/6
(2)有参宏的展开,只是将实参作为字符串,简单 地置换形参字符串,而不做任何语法检查。在定义有 参宏时,字符串内的形参通常要用括号括起来以避免 出错。 例如,在例8.5中源程序主函数中有如下语句: area2 = S(a+b); 这时,用实参代替PI*r*r中的r,替换后的宏成为: area2 = PI*a+b*a+b; 显示,这与程序设计的原意不符。为避免这种错误的 产生,经常采用的办法是将形参用括号括起来。若在 宏定义对字符串形参添加括号,即: #define S(r) PI*(r)*(r) 进行替换后得到“area2 = PI*(a+b)*(a+b)”,这样才能 实现程序设计所要达到的目的。
2019/1/6
8.2.2 带参数的宏定义
C语言允许宏带有参数。在宏定义中的参 数称为形式参数,在宏调用中的参数称为 实际参数。对带参数的宏,在调用中不仅 要宏替换,而且要用实参去代换形参。 带参数的宏定义的一般形式为: #define 宏名(参数1,参数2,…) 包含参数 的字符串 带参宏调用的一般形式为: 宏名(实参表);
2019/1/6
(8)对“输出格式”作宏定义,可以减 少书写麻烦。
例8.4对输出格式作宏定义。 #include <stdio.h> #define P printf #define D "%d\t" #define F "%.2f\n" void main(){ int a=5, c=8, e=11; float b=3.8, d=9.7, f=21.08; P(D F,a,b); P(D F,c,d); P(D F,e,f); }
2019/1/6
(5)带参的宏和带参函数很相似,但有 本质上的不同,除上面已谈到的几点外, 把同一表达式分别用函数与用宏来处理, 其结果可能不同。请看例8.6和例8.7的程 序及运行结果。
2019/1/6
例8.6
求平方数,用函数处理
#include <stdio.h> void main( ) { int SQ(int y); int i=1; while(i<=5) printf("%d\t",SQ(i++)); } int SQ(int y) { return(y*y); } 程序运行情况如下: 1 4 9 16 25
2019/1/6
在宏定义#define PI 3.14159中,用宏名 PI代替一个______ A 单精度数 B 双精度数 C 常量 D 字符串
答案:D 宏是用一个简单的名称代替 一个字符串
#define area(a) (a*a) 当调用area(2+3)时,结果为_____
2019/1/6
例8.7 求平方数,用宏处理
#include <stdio.h> #define SQ(y) (y*y) void main() { int i=1; while(i<=5) printf("%d ",SQ(i++*i++)); }
程序运行情况如下: 2 12 30
2019/1/6
4.有关宏定义的说明
(1)宏名一般用大写字母表示,以示与变 量名区别。但这并非是规定。 (2)宏定义不是语句,所以不能在行尾加 分号。否则,宏替换时,会将分号作为字符 串的1个字符,用于替换宏名。 (3)在宏替换时,预处理程序仅以按宏定 义简单替换宏名,而不作任何检查。如果有 错误,只能由编译程序在编译宏替换后的源 程序时发现。 (4)宏定义必须写在函数之外,其作用域 为宏定义命令起到源程序结束。如要终止其 作用域可使用#undef命令。
4.5↙ R=4.50 AREA=63.62
2019/1/6
对带参宏的几点说明:
(1)定义有参宏时,宏名与左圆括号之间不能留 有空格。否则,C编译系统将空格以后的所有字 符均作为替代字符串,而将该宏视为无参宏。 例如把例8.5: #define S(r) PI*r*r 写为: #define S (r) PI*r*r 将被认为是无参宏定义,宏名S代表字符串“(r) PI*r*r”。宏替换时,宏调用语句: area = S(x); 将变为: area = (r) PI*r*r(x) 这显然是错误的。
–
2019/1/6
(6)宏定义允许嵌套,在宏定义的字 符串中可以使用已经定义的宏名。在 宏替换时由预处理程序层层代换。
例如: #define PI 3.1415926 #define S PI*r*r /* PI是已定义的 宏名 */ 对语句: printf("%f",S); 进行宏替换后变为: printf("%f",3.1415926*r*r);
2019/1/6
例8.5
运用带参宏求圆的面积。
#include<stdio.h> #define PI 3.1415926 #define S(r) PI*r*r /* 带参数的宏 定义 */ void main() { float x,area; scanf("%f",&x); area = S(x); printf("R=%.2f\tAREA=%.2f\n",x,area); } 程序运行情况如下: