




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第第9章章 编译预处理编译预处理 第第9章章 编译预处理编译预处理 9.1 宏定义宏定义 9.2 文件包含文件包含 9.3 条件编译条件编译 习题习题9 第第9章章 编译预处理编译预处理 9.1 宏定义宏定义 9.1.1 无参数的宏定义 无参数宏的宏名后不带参数。其定义的一般格式为 #define 宏名 字符串 其中的“#”表示这是一条预处理命令。凡是以“#”开 头的均为预处理命令。“define”为宏定义命令。“宏名” 为所定义的宏名。“字符串”可以是常数、表达式和格式 串等。在前面介绍过的符号常量的定义就是一种无参宏定 义。此外,常对程序中反复使用的表达式进行宏定义。 第第9章章 编译预处
2、理编译预处理 1. 无参数宏定义符号常量 符号常量用无参数的宏定义语句定义,把符号 常量名定义为指定的字符串,将程序中出现宏名的地 方均用该字符串来替换。在进行编译预处理时,用该 字符串替代程序中出现的符号常量名。例如: #define TRUE 1 #define FALSE 0 把TRUE定义为1,把FALSE定义为0。在符号常量 定义之后,就可以用它来编码了。 第第9章章 编译预处理编译预处理 例如: if(i=TRUE) printf(you are right! n) ; else if(i=FALSE) printf(you are wrong! n) ; 对于该程序段,在进行编译
3、预处理时,就把程序 中出现的TRUE和FALSE分别用1和0替代,于是就变为 if(i=1) printf(you are right! n) ; else if(i=0) printf(you are wrong! n) ; 第第9章章 编译预处理编译预处理 在符号常量定义语句中,字符串可以是一个数值型数 据、表达式或字符串。例如: #define PI 3.1415926 #define S (PI*r*r) #define PRT printf #define A (20-(3*4) 如果字符串是一个运算表达式,一般应该用括号括 住它,以便把它视为一个操作对象与其他操作数进行运算, 否则
4、,会由于操作优先级问题而发生错误。例如: text = A*8 ; 进行编译预处理后,该表达式变为 text = (20-(3*4)*8 ; 第第9章章 编译预处理编译预处理 如果A定义为 #define A 20- (3*4) 则表达式text = A*8经预编译后变为 text = 20- (3*4)*8 ; 这就不符合原意。因此,在宏定义语句中的字符 串为一般表达式(而不是一个操作数)时,为了保证正确 的运算次序,应该用括号括住它。因此在宏定义时必 须十分注意,应保证在宏代换之后不发生错误。 第第9章章 编译预处理编译预处理 2. 无参数宏的好处 在程序设计中,使用无参数的宏有下面两点好
5、处: 1) 增强程序的可读性 以符号常量为例,由于符号常量含义明确,于是采用 符号常量书写的程序要比不采用符号常量的可读性强。例 如: #define LENGTH 20 #define WIDTH 40 #define HEIGTH 60 在程序中用LENGTH、WIDTH、HEIGTH时,一看就 知道它们分别代表长、宽、高,而如果直接用20、40、60, 则很难猜出它们是长、宽、高。 第第9章章 编译预处理编译预处理 2) 增强程序的可维护性 如果一个常量在程序中多次被引用,则可把它定义为 符号常量。这样,在以后需改动该常量时,只需改动它的宏 定义语句即可,而不必对每一个引用它的地方进行修
6、改。这 不但可以减少修改的工作量,而且可以避免漏改。 3. 无参数宏的注意事项 使用无参数宏定义符号常量时,一般应注意以下几点。 (1) 宏定义是用宏名来表示一个字符串,在宏展开时又 以该字符串取代宏名,这只是一种简单的代换,字符串中可 以含任何字符,可以是常数,也可以是表达式,预处理程序 对它不作任何检查。如有错误,则只能在编译已被宏展开后 的源程序时发现。 第第9章章 编译预处理编译预处理 (2) 符号常量名一般用大写字母(也可以用小写字母)表 示,以便与其他标识符相区别。符号常量名的命名规则与 一般标识符相同。另外,应考虑在字符串中根据需要加上 括号。 (3) 宏定义不是说明或语句,因此
7、,不能用分号结尾。 如果加上分号,则分号被作为字符串的一部分,连分号也 一起置换。例如: #define A 60 ; 上面的格式表示A被定义为“60 ;”,而不是“60”。于 是,在预编译时,程序中凡是出现A的地方,都用“60 ;” 替换。这就不符合原意了。 (4) 替换字符串可以为空。 第第9章章 编译预处理编译预处理 (5) 宏定义语句应放在函数定义之外,符号常量的 有效范围是从定义它的宏定义语句开始至所在源文件 的结尾。一般宏定义语句都放在源文件的开头,以便 使它对整个源文件都有效。 (6) 为了灵活控制宏定义的作用范围,可用“ undef”命令终止宏定义的作用域。 第第9章章 编译预
8、处理编译预处理 例如: #define PI 3.14159 main( ) # undef PI /* PI的宏定义结束 */ f1( ) 表示PI只在main函数中有效,在f1中无效。 第第9章章 编译预处理编译预处理 (7) 宏定义允许嵌套,在宏定义的字符串中可以使用已经 定义的宏名。在宏展开时由预处理程序层层代换。例如: #define PI 3.14 #define R 10 #define S PI*R*R main( ) printf(S=%f , S); 预编译后,该程序变为 main( ) printf(S=%f , 3.14*10*10); 第第9章章 编译预处理编译预处理
9、 (8) 宏名在源程序中若用引号括起来,则预处理程序不 对其作宏代换。例如: #define NO 220 main( ) printf(NO); printf(n); 上例中定义宏名NO表示220,但在printf语句中NO被引 号括起来,因此不作宏代换。程序的运行结果为 NO 表示把“NO”当字符串处理。 第第9章章 编译预处理编译预处理 【例9-1】假设血压正常值低压为70,高压为120。 如果低压高于70,并且高压低于120,则为正常。从键 盘输入血压值,判断该血压值是否正常。 #include main( ) #define LOW 70 /* 定义宏 */ #define HIGH
10、 120 /* 定义宏 */ 第第9章章 编译预处理编译预处理 int bloodplow , bloodphigh ; do scanf(%d%d , while(bloodplow=bloodphigh) ; if(bloodplowLOW else printf(you may have something wrong!) ; 输入:130 80 输出:you may have something wrong! 第第9章章 编译预处理编译预处理 【例9-2】已知一梯形的上下两边的长分别为a、b,输 入高h,求其面积。 #include main( ) #define a 5/* 定义宏
11、*/ #define b 15/* 定义宏 */ #define L (a+b)/* 嵌套定义宏 */ 第第9章章 编译预处理编译预处理 float h , s ; scanf(%f , s=h*L/2 ; printf(s=%f n , s) ; 输入:3 输出:s=30.000000 第第9章章 编译预处理编译预处理 【例9-3】利用迭代法求方程的根。其迭代公式为 yi+1=(yi+x/yi)/2。 #include stdio.h main( ) #define ABS 1e-4 float y1 , y , x ; printf(x=) ; scanf(%f , printf(y=)
12、; scanf(%f , do 第第9章章 编译预处理编译预处理 y1=y ; y=(y1+x/y1)/2 ; while(y1-y)ABS) ; printf(%fn , y) ; 运行结果: x=2 y=3 1.414214 第第9章章 编译预处理编译预处理 9.1.2 带参数的宏定义 1. 带参数的宏的定义 利用#define语句不仅可以定义符号常量,也可以定义 带参数的宏。带参数的宏的一般定义格式为 #define 宏名(参数表) 字符串 字符串中包含参数表中的参数。 调用带参数宏的一般格式为 宏名(实参表); 例如: #define MIN(a,b) (a)(b)? (a) : (b
13、) 第第9章章 编译预处理编译预处理 其中,MIN(a,b)是带参数的宏,a和b是形式参数。 该定义把MIN(a,b)定义为“(a)(b)? (a):(b)”。在定义 了该宏后,就可在程序中用MIN(a,b)替代定义它的运 算表达式“(a)(b)? (a):(b)”。宏的使用方法类似函 数。例如,在需要求两个数的最小值时,就可以使用 已定义的宏。 c= MIN(10,20) ; 在进行编译时,预编译程序根据宏定义式来替换 程序中出现的带参数的宏,其中定义式中的形式参数 用相应的实际参数替换。于是,上面的赋值语句变为 c= MIN(10=0)? (x): -(x) /* 求x的绝对值 */ #d
14、efine MAX(a,b) (a)b)?a:b 改写为 #define MAX(a,b) (ab)?a:b 将被认为是无参宏定义,宏名MAX代表字符串 “(a,b) (ab)?a:b”。宏展开时,宏调用语句: max=MAX(x,y); 将变为 max=(a,b)(ab)?a:b(x,y); 这显然是错误的。 第第9章章 编译预处理编译预处理 【例9-4】键盘输入立方体的边长a,求其表面积s 及体积v。 #include main( ) #define L(a,s,v) s=6*a*a ; v=a*a*a int a1,s1,v1; a1=0 ; scanf(%d, L(a1,s1,v1)
15、; printf(%d , %d , %dn , a1 , s1 , v1) ; 第第9章章 编译预处理编译预处理 【例9-5】求1100所有奇数的和。 #include main( ) #define ISODD(x) (x)%2=1)? 1:0) int sum , i ; sum=1 ; for(i=3 ; i=100 ; i+) if ISODD(i) sum+=i ; printf(%dn , sum) ; 第第9章章 编译预处理编译预处理 【例9-6】已知某单位上缴个人所得税的算法如下: 输入工资,求其应上缴的税款。 #include main( ) #define TAX1(a)
16、 (a=800) ? 0 : (a1300)? 0.05 : (a=2800) ? 0.1 : (a=5800) ? 0.15 : 0.2) #define TAX2(b) (b=1300) ? 0 : (b=2800)? 25 : (b=5800)? 125 : 375) #define TAX3(c) c*TAX1(c)-TAX2(c) 第第9章章 编译预处理编译预处理 float tax , wage ; scanf(%f , tax=TAX3(wage) ; printf(%f , %fn , wage , tax) ; 第第9章章 编译预处理编译预处理 【例9-7】输入4个整数,按由
17、小到大的顺序输出。 #include main( ) #define CHANGE(a,b) int t ; t=a; a=b; b=t ; int i , j , k , l ; printf(please input four number:) ; scanf(%d , %d , %d , %d , 第第9章章 编译预处理编译预处理 if(ij) CHANGE(i , j) ; if(ik) CHANGE (i , k) ; if(il) CHANGE (i , l) ; if(jk) CHANGE (j , k) ; if(jl) CHANGE (j , l) ; if(kl) CHAN
18、GE (k , l) ; printf(the proper order is:) ; printf(%d %d %d %dn , i , j , k , l) ; 第第9章章 编译预处理编译预处理 9.2 文件包含文件包含 在前面章节中,我们经常在编写程序中,会写上 下面的语句: #include 其含义是在编译时,用stdio.h头文件的内容替换该 语句。 文件包含语句的一般格式为 #include 文件名 或 #include 第第9章章 编译预处理编译预处理 其中,是被包含文件的文件名,它是一个磁盘 文件。该预编译语句的功能是要将 所指文件的全部内容包含在该#include语句所 在的
19、源文件中。也就是说,在预编译时,用所指 文件的全部内容替换该#include语句行,使该文件成为这个 源文件的一部分。 在#include语句的书写格式中,被包含文件的文件名可 用尖括号()括住,也可以用双引号( )括住。 当用尖括号括住时,表示编译系统按系统设定的标准目 录搜索文件;当用双引号括住时,表示按指定的路径搜索。 若未指定路径名时,则在当前目录中搜索。 第第9章章 编译预处理编译预处理 文件包含语句是很有用的语句,特别是对包括多个源 文件的大程序来说,可以把各个源文件中共同使用的函数 说明、符号常量定义、外部量说明、宏定义和结构类型定 义等写成一个独立的包含文件,在需要这些说明的源
20、文件 中,只需在源文件的开头用一个#include语句把该文件包括 进来,这样就可以避免重复工作。例如: /* file1.c */ #include file2.h main( ) /*file2.h*/ #define PI 3.14159 第第9章章 编译预处理编译预处理 做成包含文件的另一个好处是,当这些常量、宏定义 等需要修改时,只需修改这个被包含的文件即可,而不必 修改各源文件。 使用#include语句时,应注意以下两点: (1) 一个include命令只能指定一个被包含文件,若有 多个文件要包含,则需用多个include命令。 (2) 文件包含允许嵌套,即在一个被包含的文件中又
21、可 以包含另一个文件。 第第9章章 编译预处理编译预处理 9.3 条件编译条件编译 一般情况下,源程序中所有的行都参加编译,但 有时在写程序时要求根据具体情况编译不同的程序代 码,C语言中提供了条件编译,可以按不同的条件去编 译不同的程序部分,因而产生不同的目标代码文件。 这对于程序的移植和调试是很有用的。条件编译有3种 形式,下面分别介绍。 第第9章章 编译预处理编译预处理 1. #ifdef #else #endif语句 用# ifdef # else # endif语句进行条件编译的指令 格式为 #ifdef 标识符 程序段1 #else 程序段2 #endif 其作用是:如果标识符已被
22、定义(用#define定义),则对 程序段1进行编译,而程序段2被删除;否则,程序段1被删 除,编译程序段2。其中,#else部分是可以缺省的,即 第第9章章 编译预处理编译预处理 #ifdef 标识符 程序段1 #endif 条件编译语句中的#ifdef和#endif决定了编译范围, 在此范围外的源程序不存在条件编译问题。条件编译 对于提高程序的移植性很有帮助。 第第9章章 编译预处理编译预处理 【例9-8】条件编译#ifdef的使用。 #include stdio.h #define TED 10 main ( ) #ifdef TED printf(Hi Tedn); /* 如果定义了T
23、ED,则编译此行代码 */ #else printf(Hi anyonen); /* 如果没用定义TED,则编译此行代码 */ 第第9章章 编译预处理编译预处理 printf(Hi anyonen); /* 如果没用定义TED,则编译此行代码 */ #endif #ifndef RALPH printf (RALPH not definedn); /* 如果定义了RALPH,则编译此行代码 */ #endif 上述代码打印“Hi Ted”及“RALPH not defined”。如 果TED没有定义,则显示“Hi anyone”,后面是“RALPH not defined”。可以像嵌套#if
24、那样将#ifdef 与# ifndef 嵌套至 任意深度。 第第9章章 编译预处理编译预处理 2. #ifndef #else #endif语句 由#ifndef #else #endif语句进行条件编译的指令格式 为 #ifndef 标识符 程序段1 #else 程序段2 #endif 与第一种形式的区别是将“ifdef”改为“ifndef”。它的功 能是:如果标识符未被#define命令定义,则对程序段1进行 编译,否则对程序段2进行编译。这与第一种形式的功能正 相反。例如: 第第9章章 编译预处理编译预处理 #ifndef UNPRN printf(Name= %s sa= %f, na
25、me , s) ; #else printf(%s %f , name , s) ; #endif 当UNPRN在程序段之前未定义时,则只编译 “printf(Name= %s sa= %f, name , s) ;”。如果在该程 序段之前加一行: #define UNPRN 1 则只编译“printf(%s %f , name , s) ;”。其中, UNPRN可定义为任何字符串。 第第9章章 编译预处理编译预处理 3. #if #else #endif语句 由#if # else # endif语句进行条件编译的指令格式为 #if 表达式 程序段1 #else 程序段2 #endif 其作
26、用是:当表达式的值为非0时,编译程序段1,不编 译程序段2;否则编译程序段2(其中#else部分是可以缺省的)。 例如,在程序设计的测试阶段,经常要显示一些变量的信息, 以检查是否正确,而在正式执行时,却不需要显示这些信息。 这时,就可以用下面形式的条件编译。 第第9章章 编译预处理编译预处理 #define DEBUG 1 #if DEBUG printf(a=%d b=%f c=%s , a , b , c) ; #endif 以上形式的条件编译适用测试阶段,如果程序测 试完成,在编译正式的执行代码时,只需把DEBUG定 义为0即可。在进行条件编译时,可根据情况选择条件 编译语句。 第第9章章 编译预处理编译预处理 【例9-9】条件编译#if的使用。 #include stdio.h #define R 1 main( ) float c,r,s; printf (input a number: ); scanf(%f, #if R 第第9章章 编译预处理编译预处理 r=3.14159*c*c; /* 如果R非0,则编译此行和下一行代码 */ printf(area of round is: %fn,r); #else s=c*c; /* 如果R为0,则编译此行和下一行代码 */ printf(area of square is: %fn,s); #endi
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 第10课 清新空气是个宝 第1课时 教学设计-2023-2024学年道德与法治二年级下册统编版
- 创业成功人士案例分析
- 2024年新人教版七年级上册地理教学课件 大单元整体设计-第二章
- Unit 4 My Family Chinese and English names 教学设计 2024-2025学年冀教版(2024)七年级英语上册
- 记账公司述职报告
- 计算机安全和维护
- 60岁雇佣合同范例
- 出口合同范例封面
- 预防踩踏讲话稿
- 鲁滨逊漂流记读书心得(15篇)
- 二零二五年度医疗健康产业贷款担保合同
- 2025年安徽医学高等专科学校单招职业适应性测试题库及答案一套
- 2025年赣西科技职业学院单招职业技能测试题库带答案
- 急性ST段抬高型心肌梗死溶栓治疗专家共识2024解读
- 电影《哪吒之魔童降世》主题班会
- 中国卒中学会急性缺血性卒中再灌注治疗指南+2024解读
- 2024年高中历史 第2课 中华文化的世界意义说课稿 部编版选择性必修3
- 2025年湖南科技职业学院高职单招高职单招英语2016-2024历年频考点试题含答案解析
- 中国心力衰竭诊断和治疗指南2024解读(完整版)
- 2024医疗机构重大事故隐患判定清单(试行)学习课件
- (正式版)JBT 7248-2024 阀门用低温钢铸件技术规范
评论
0/150
提交评论