首页计算机计算机软件C语言程序设计 06 第5章 编译预处理.pptx

06 第5章 编译预处理.pptx

页数:30页文件大小:219.4 KB来源: C语言程序设计ppt课件

本课件先说明编译预处理在编译流程中的位置与作用,随后讲解不带参数宏的定义形式、作用域与宏展开规则,带参数宏的展开与易错之处;接着介绍文件包含的两种查找形式,最后给出条件编译的几种形式及其在程序移植与调试中的应用。

第5章 编译预处理,讲解1.了解预编译的概念、3.了解“文件包含”与预处理的应用、4.了解条件编译的几种形式等内容
什么是编译预处理编译预处理是指,展示宏定义:#define、条件编译:#if_#else_#en、
不带参数宏定义,展示形式:#define宏名[字符串]字、定义位置:任意等示例代码与运行结果
查看本课件的文字版(共 30 页,供检索与复制)

第1页:第5章 编译预处理

第5章 编译预处理

教学内容1.了解预编译的概念,2.掌握宏定义的方法(主要是无参)。

3.了解“文件包含”与预处理的应用。

4.了解条件编译的几种形式。

教学要求5.1概述5.2宏定义5.3文件包含5.4条件编译结束5.5小结

第2页:什么是编译预处理编译预处理是指

什么是编译预处理编译预处理是指

在进行编译之前,先对源程序中的编译预处理命令进行处理;然后再将处理的结果,和源程序一起进行编译,以得到目标代码。5.1概述

#include
  • 宏定义:#define
  • 条件编译:#if_#else_#endif
  • "#"开头
  • 占单独书写行
  • 语句尾不加分号

第3页:不带参数宏定义

不带参数宏定义

功能:用指定标识符(宏名)代替字符序列(宏体)如:#defineYES1#defineNO0#definePI3.1415926#defineOUT

printf("Hello,World");
  • 一般形式:#define宏名[字符串]字符串表示宏名,可缺省,定义过或取消宏体。
  • 定义位置:任意(一般在函数外面)

第4页:作用域

作用域

从定义命令到文件结束;可终止作用域,格式:#undef宏名例:#defineYES1

main(){ …… } #undefYES……#defineYES0max(){ …… } 5.2宏定义YES新作用域YES原作用域

第5页:宏展开

宏展开

预编译时,用宏体替换宏名如:#defineYES1#defineNO0……if(x==YES)

printf("correct!"); elseif(x==NO)printf("error!");
printf("2*P=%f",2*P); 5.2宏定义展开后:if(x==1)printf("correct!"); elseif(x==0)printf("error!"); 不作语法检查宏展开:printf("2*P=%f",2*3.1);
  • 引号中的内容不置换如:#defineP3.1

第6页:宏定义不能递归如

宏定义不能递归如

宏定义中使用必要的括号“()”如:上例宏展开:(若是求长方形周长就错了)var=80+40*2;5.2宏定义(WIDTH+40)(80 + 40)

  • #defineMAXMAX+10(
  • )
  • 宏定义可嵌套如:#defineWIDTH80defineLENGTHWIDTH+40var=LENGTH*2

第7页:例1*给出下面宏替换的结果

例1*给出下面宏替换的结果

#defineR5.0#defineFORMAT"Area=%f\n"#definePI3.14#defineAREAR*R*PI#definePRprintf

main(){ PR(FORMAT,AREA); PR("FORMAT"); } 5.2宏定义运行结果:Area =78.500000FORMATmain()//宏替换的结果{ printf("Area=%f\n",5.0*5.0*3.14); printf("FORMAT"); }

第8页:带参数宏定义转下一部分

带参数宏定义转下一部分

  • 一般形式:#define宏名(参数表)宏体
  • 宏展开:形参用实参换,其它字符保留例:#defineS(a,b)a*b……area=S(3,2);宏展开:area=3*2
  • 宏名与左圆括号之间不能留有空格例:#defineS
  • (r)PI*r*r相当于定义了不带参宏S,代表字符串"(r)PI*r*r"

第9页:宏体及各形参外一般应加括号()例

宏体及各形参外一般应加括号()例

#definePOWER(x)x*xx=4;y=6;z=POWER(x+y);宏展开:z=x+y*x+y;//不是所要的结果一般写成:#definePOWER(x)((x)*(x))宏展开:z=((x+y)*(x+y));

第10页:例2*用带参数宏定义求两个数的最大值

例2*用带参数宏定义求两个数的最大值

#include<stdio.h>main(){ inta,b,c; floatx,y,z; scanf("%d%d",&a,&b); c=MAX(a,b); scanf("%f%f",&x,&y); z=MAX(x,y); printf("c=%dz=%f\n",c,z); } 5.2宏定义宏展开c = (a)>(b)?(a):(b)宏展开z = (x)>(y)?(x):(y)运行结果:3
  • #defineMAX(x,y)(x)>(y)?(x):(y)
  • 87
  • c=87 z=

第11页:带参的宏与函数区别

带参的宏与函数区别

2宏定义函数带参宏区别程序运行时编译时处理时间定义实参,形参类型无类型问题参数类型分配内存先求实参值,再代入形参不分配内存简单的字符置换处理过程不变变长程序长度调用和返回占时间不占运行时间运行速度

第12页:在定义和使用宏调用时应注意的问题

在定义和使用宏调用时应注意的问题

  • 参数多次计算如定义:#definemin(A,B)((A)<(B)?(A):(B))
  • 调用1:z=min(x+y,x*y);展开:z=((x+y)<(x*y)?(x+y):(x*y))
  • 调用2:z=min(n++,m++);展开:z=((n++)<(m++)?(n++):(m++))
  • 两个调用都出现参数表达式计算多次的问题,可能会成为程序中的隐含错误。

第13页:运算符优先级引起的问题

运算符优先级引起的问题

  • 定义:#definesquare(x)x*x调用:z=square(x+y);展开:z=x+y*x+y
  • 算符“*”的优先级高于“+”的优先级,接开表达式中,将首先计算y*x,与题意不符。
  • 应加括号该定义为:#definesquare(x)((x)*(x))

第14页:宏定义中的字符串相连顺序书写

宏定义中的字符串相连顺序书写

的两个字符串间仅由空格、换行符或制表符分隔,编译时,自动将这两个串连接。如:#defines1"123"#defines2"ABC"# definess1

s2//连接s1和s2,s为"123ABC"4.符号常量(重点掌握)在定义无参宏时,若“语言符号字符串”是一个常量,则相应的“宏名”就是一个符号常量。

如:#defineEOF-1//文件尾#defineNULL0//空指针

第15页:使用宏定义的优点

使用宏定义的优点

  • 可提高源程序的可维护性
  • 可提高源程序的可移植性
  • 减少源程序中重复书写字符串的工作量

第16页:概念用

概念用

#include开始的预处理命令称文件包含命令。文件包含是指,一个源文件可以将另一个源文件的全部内容包含进来。二、一般格式#include<文件名>或#include"文件名"
  • <文件名>:直接按标准目录搜索。
  • "文件名":先在当前目录搜索,再搜索标准目录,可指定路径。

第17页:预处理过程按规定方法寻找文件

预处理过程按规定方法寻找文件

若找到,用被包含文件的内容取代该预处理命令,再对“包含”后的文件作一个源文件编译;

若找不到,则预编译出错,提示无法打开相应文件。

5.3文件包含file2.cfile1.c

#include"file2.c"A取代BB

第18页:文件包含的优点

文件包含的优点

有了文件包含处理功能,就可以将多个模块共用的数据(如符号常量和数据结构)或函数,集中到一个单独的文件中。

这样,凡是要使用其中数据或调用其中函数的人,只要使用文件包含,将所需文件包含进来即可,不必再重复定义它们,从而减少重复劳动。

  • 一个大程序,通常分为多个模块,并由多个人分别编程。

第19页:5.3 文件包含

5.3 文件包含

一条包含命令,只能指定一个被包含文件。如果要包含n个文件,则要用n条包含命令。5.3文件包含file2.cfile1.c

#include命令行应写在程序的开头。
#include"file2.c"#include"file3.c"A取代BBfile3.c取代CC

第20页:文件包含可以嵌套

文件包含可以嵌套

#include"file3.c"Bfile3.cCCfile1.c#include"file2.c"ACBfile2.c#include"file3.c"B取代取代
  • 即被包含文件中又包含另一个文件。
  • 包含文件修改后,包含该文件的源程序必须重新编译。5.3文件包含file2.c

第21页:前面例子中

前面例子中

头文件主要内容是标准库函数的原型说明、一些系统使用的符号常量(如EOF、NULL)定义等。

#include命令包含的是系统标准库的各种头文件(如stdio.h、math.h):
#include命令将这种文件包含进程序,相当于在源程序的前面书写了这些函数原型,
#include命令并将#include

第22页:标准库的所有头文件在"C

标准库的所有头文件在"C

\ProgramFiles(x86)\MicrosoftVisualStudio\VC98\Include"目录下,可以打开此目录查看其中的内容,但千万不要试图修改它。

“C:\ProgramFiles(x86)”是VC安装目录,不同的机器可能不一样。

例3一个包含文件的实例本例中,format.h用#define定义了一组输出格式,在随后的主程序中用这些格式输出若干个变量的值。

编辑生成format上的方法与编辑普通C源程序一样,保存文件时给它指定合适的名称和后缀就可以了。

第23页:5.3 文件包含

5.3 文件包含

printf("%d""%d""\n",a,b); "%d%d\n"主函数如下:# include"format.h"//可指定完整路径main(){ inta, b, c, d ; a = 1; b = 2; c = 3; d = 4; printf(D1,a); printf(D2, a, b); printf(D3, a, b, c); printf( D4,a,b,c,d); } 文件format.h如下:# defineNL "\n"#defineD "%d"#defineD1 D NL#defineD2 D D1#defineD3 D D2#defineD4 D D3展开连接运行结果:11 21 2 31 2 3 4

第24页:5.4 条件编译转下一部分

5.4 条件编译转下一部分

概念通常源程序中所有的行都参加编译,但有时希望源程序中的某些行只在满足一定条件下才进行编译,有时又希望满足某一条件时对一组语句进行编译,不满足这一条件时编译另一组语句,这就是“条件编译”。

二、作用划出源程序的一些片段,使预处理程序可以根据一定条件确定保留或丢掉某个片段,或确定从几个片段中选取哪一个片段保留下来。

第25页:三种使用格式

三种使用格式

命令格式1根据标识符是否用#define命令定义过来选择保留“程序段1”或“程序段2”。

上面左右两种形式的选择方法正好相反。

5.4条件编译#ifdef标识符程序段1#else程序段2#endif#ifndef标识符程序段1#else程序段2#endif

第26页:命令格式2根据表达式值是否为真

命令格式2根据表达式值是否为真

命令格式3根据多个表达式值,从若干段中选一段。

5.4条件编译# if表达式程序段1# else程序段2#endif# if表达式1程序段1#elif表达式2程序段2#elif表达式3…# else程序段n#endif

  • 选择保留程序段1还是程序段2。

第27页:5.4 条件编译

5.4 条件编译

条件编译的选取语句操作是在预处理阶段完成的,因此,预处理命令中的表达式都应该是预处理阶段可以求值的表达式。

预处理完成之后,所有的预处理命令没有了,得到的是预处理命令展开或选择好的结果。

条件编译可有效地提高程序的可移植性,并广泛地应用在商业软件中,为一个程序提供各种不同的版本。

  • 采用条件编译,可以减少被编译的语句,从而减少目标程序的长度,缩短运行时间。

第28页:例4一个条件编译例子调试程序时

例4一个条件编译例子调试程序时

经常要打印一些跟踪信息,调试结束后,我们希望这些信息不再出现。

但是,这些信息对于我们将来修改程序、重新调试相当重要。

本例使用条件编译处理这些打印行,使用一个调试宏定义DEBUG来实现对调试行的选择控制。

条件编译的形式如下:#defineDEBUG1#ifDEBUG…//此处为打印行或调试行#endif

第29页:调试程序时

调试程序时

DEBUG定义为1;

调试结束,DEBUG定义为0。

可在所有调试及打印行处加入本例的条件编译命令。

下面是一段示例程序:#defineDEBUG1//宏名字用大写字母

#include<stdio.h>//在源程序中非常醒目main(){ #ifDEBUG//DEBUG为表达式printf("Thisistestingline\n"); #endifprintf("Thisisnormalline\n"); }

第30页:本章内容不多但很实用,出现的预处理命令

本章内容不多但很实用,出现的预处理命令

#include,#if,#elif,#else,#endif,#ifdef,#idndef。
  • 有:#define,
  • 学习本章后应掌握的知识点如下:
  • 宏定义的作用,代参宏定义的定义方法,宏调用和函数调用的区别,宏展开的方法。
  • 包含命令在多文件程序中的使用,常用头文件及相关函数的使用。
  • 条件编译的几种实现方法,如何使用控制条件编译的宏定义。多文件程序的组织和实现方法。
顶部目录