《kj-第8章预处理命令ppt课件(全).ppt》由会员分享,可在线阅读,更多相关《kj-第8章预处理命令ppt课件(全).ppt(24页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第第8章章 预处理命令预处理命令l本章概述 l本章的学习目标l主要内容l本章概述l本章介绍宏定义的两种形式,介绍本章介绍宏定义的两种形式,介绍文件包含的使用方法文件包含的使用方法,介绍条件编介绍条件编译的概念。译的概念。第第8章章 预处理命令预处理命令本章的学习目标本章的学习目标:本章教学目的:本章教学目的:掌握宏定义的两种形式,掌握文掌握宏定义的两种形式,掌握文件包含的使用方法了解条件编译的概念。件包含的使用方法了解条件编译的概念。本章教学重点:本章教学重点:宏定义的两种形式,文件包含的宏定义的两种形式,文件包含的使用方法。使用方法。本章教学难点:本章教学难点:带参数的宏定义。带参数的宏定义
2、。第第8章章 预处理命令预处理命令第第8章章 预处理命令预处理命令l8.1 宏定义宏定义 l8.2 “文件包含文件包含”处理处理 l8.3 条件编译条件编译 l8.4 本章小结本章小结主要内容主要内容:编编译译预预处处理理是是指指一一些些行行首首以以#开开头头的的特特殊殊语语句句,必必须须在在对对程程序序进进行行通通常常的的编编译译之之前前,先先对对程程序序中中这这些些特特殊殊的的命命令令进进行行“预预处处理理”,即即根根据据预预处处理理命命令令对对程程序序作作相相应应的的处处理理(例例如如,若若程程序序中中用用#definedefine命命令令定定义义了了一一个个符符号号常常量量A A,则则
3、在在预预处处理理时时将将程程序序中中所所有有的的A A都都置置换换为为指指定定的的字字符符串串)。经经过过预预处处理理后后程程序序不不再再包包括括预预处处理理命命令令了了,最最后后再再由由编编译译程程序序对对预预处处理理后后的的源源程程序序进进行行通通常常的的编编译译处处理理,得得到到可可供供执执行行的的目目标标代代码码。C C语语言言与与其其它它高高级级语语言言的的一一个个重重要要区区别别是是可可以以使使用用预预处处理理命命令令和和具具有有预处理的功能。预处理的功能。第8章 预处理命令C提供的预处理功能主要有以下三种:提供的预处理功能主要有以下三种:宏定义、文件包含和条件编译宏定义、文件包含
4、和条件编译它们分别用宏定义命令、文件包含命令和条件编译命令来实现。为了与一般C语句相区别,这些命令以符号“”开头。8.1 宏定义 宏定义指的是用宏定义指的是用#define定义的命令行,有不带定义的命令行,有不带参数和带参数两种形式。参数和带参数两种形式。8.1.1 不带参数的宏定义不带参数的宏定义不带参数的宏定义的一般形式为:不带参数的宏定义的一般形式为:#define#define 标识符标识符 字符串字符串含义是用指定的宏名(即标识符)来代表其后字符串。含义是用指定的宏名(即标识符)来代表其后字符串。例如例如:#define SIZE 10000#define SIZE 10000#de
5、fine PI 3.1415926#define PI 3.1415926#define FORMAT “%d#define FORMAT “%d,%d%d,%dn”%dn”作用是指用标识符作用是指用标识符SIZESIZE来代替字符串来代替字符串“1000010000”,用标识符用标识符PIPI来代替字符串来代替字符串“3.14159263.1415926”,用标识符用标识符FORMATFORMAT来代替字符串来代替字符串“%d“%d,%d%d,%dn”%dn”,在在编编译译预预处处理理时时,将将程程序序中中在在该该命命令令以以后后出出现现的的所所有有的的SIZESIZE用用100001000
6、0代代替替、PIPI用用3.14159263.1415926代代替替、FORMATFORMAT用用“%d“%d,%d%d,%dn”%dn”代代替替。这这种种方方法法使使用用户户能能以以一一个个简简单单的的名名字字代代替替一一个个长长的的字字符符串串,可可以以减减小重复编程工作量,而且不容易出错。小重复编程工作量,而且不容易出错。把把定定义义时时所所用用的的标标识识符符称称为为“宏宏名名”,即即SIZESIZE、PIPI和和FORMATFORMAT都都是是宏名。在预编译时将宏名替换成字符串的过程称为宏名。在预编译时将宏名替换成字符串的过程称为“宏展开宏展开”。注意:宏名习惯用大写字母表示。定义宏
7、与定义变量含义不同,宏定注意:宏名习惯用大写字母表示。定义宏与定义变量含义不同,宏定义只是作字符替换,并不给宏名分配内存空间。义只是作字符替换,并不给宏名分配内存空间。例例8.1#include#define SIZE 5int main()int i,sum=0;int dataSIZE;for(i=0;iSIZE;i+)scanf(“%d”,&datai);sum=sum+datai;printf(“sum=%dn”,sum);return 0;运行此程序可计算运行此程序可计算5个数组元素值的总和。个数组元素值的总和。对宏定义的说明:对宏定义的说明:(1)(1)定义宏的目的是提高程序的可读
8、性和通用性,便于程序的修定义宏的目的是提高程序的可读性和通用性,便于程序的修改。例如若要把例改。例如若要把例8.18.1中数组中数组datadata的元素个数改变为的元素个数改变为1010,则只要将,则只要将“#define SIZE 5#define SIZE 5”改为改为“#define SIZE 10#define SIZE 10”即可,程序中的其它语即可,程序中的其它语句均不用修改。句均不用修改。(2)(2)不不要要在在宏宏定定义义的的行行末末加加分分号号,因因为为宏宏定定义义不不是是C C语语句句,加加分分号号后,会将分号也作为字符串的组成部分,宏展开后可能出现错误。后,会将分号也作
9、为字符串的组成部分,宏展开后可能出现错误。(3)(3)宏宏定定义义可可以以出出现现在在程程序序的的任任何何位位置置,一一般般位位于于文文件件开开头头,写写在在函函数数的的外外面面。宏宏名名的的有有效效范范围围是是从从定定义义处处到到本本源源文文件件结结束束。可可以以用用#undef#undef命令终止宏定义的作用域。例如:命令终止宏定义的作用域。例如:#define PI 3.1415926#define PI 3.1415926 int main()int main()#undef PI#undef PI 由由于于#undef#undef的的作作用用,使使PIPI的的作作用用范范围围在在#u
10、ndef#undef行行处处终终止止。若若在在#undef PI#undef PI之后再出现之后再出现PIPI,则是无效的。,则是无效的。(4)(4)宏定义是用宏名代替一个字符串,凡在宏定义有效范围内的宏名都宏定义是用宏名代替一个字符串,凡在宏定义有效范围内的宏名都用该字符串代替,但要注意:双引号内的与宏名相同的字符串不认为是宏用该字符串代替,但要注意:双引号内的与宏名相同的字符串不认为是宏名,不进行替换。名,不进行替换。例如:例如:#define YES 1#define YES 1 printf(“YES”);printf(“YES”);程序将显示程序将显示YESYES,而不是,而不是1
11、1。(5)(5)可以引用前面已经定义的宏名来定义新的宏,例如:可以引用前面已经定义的宏名来定义新的宏,例如:define I1 30define I1 30 define I2 60define I2 60 define J I1+I2define J I1+I2 define K J*2+J/2+I2define K J*2+J/2+I2 这里这里J J引用了引用了I1I1和和I2I2,K K引用了引用了J J和和I2I2。注意注意K K展开是:展开是:30+60*2+30+60/2+6030+60*2+30+60/2+60,不要以为是:不要以为是:(30+60)*2+(30+60)/2+6
12、0(30+60)*2+(30+60)/2+60。除非前面的定义是:除非前面的定义是:define J (I1+I2)define J (I1+I2)。8.1.2 带参数的宏定义带参数的宏定义 带参数的宏定义的一般形式为:带参数的宏定义的一般形式为:#define#define标识符标识符(形参表形参表)字符串字符串 带带参参数数的的宏宏展展开开时时,还还要要进进行行参参数数替替换换。宏宏定定义义中中形形参参表表中中的的形形参,在程序中将用实参替换。参,在程序中将用实参替换。例如:例如:#define PI 3.14159#define PI 3.14159#define V(r)4*PI*r*
13、r*r/3#define V(r)4*PI*r*r*r/3 V(r)V(r)为为带带参参数数的的宏宏,例例如如在在程程序序中中使使用用V(6)V(6)时时,是是用用6 6代代替替宏宏定定义义中中的的形形式式参参数数r r,V(6)V(6)展展开开为为:4*3.14159*6*6*6/34*3.14159*6*6*6/3,这这是是用用来来计计算算半径为半径为6 6的球的体积。的球的体积。l例8.2l#include l#define S(a,b,h)(a+b)*h/2l int main()l int c1=6,c2=8,c3=10;l printf(“S=%dn”,S(c1,c2,c3);l
14、return 0;l S(c1,c2,c3)展开为:展开为:(c1+c2)*c3/2。程序实际执行的是下面的。程序实际执行的是下面的输出语句:输出语句:printf(“S=%dn”,(c1+c2)*c3/2);如果将上面的如果将上面的S(c1,c2,c3)换成换成S(6,c2,2+8),运行程序,运行程序后,输出结果还是后,输出结果还是70吗?吗?在在使使用用带带参参数数的的宏宏定定义义时时,宏宏名名和和括括号号之之间间不不能能有有空空格格,否否则则系系统统会会把把括号、形参和字符串认为是一个字符串。括号、形参和字符串认为是一个字符串。例如,如果有例如,如果有 define S (x,y)x*
15、ydefine S (x,y)x*y 会被认为:会被认为:S S是符号常量(不带参的宏名),它代表字符串是符号常量(不带参的宏名),它代表字符串“(x,y)x*y(x,y)x*y”。上上面面介介绍绍的的用用带带参参数数的的宏宏求求球球的的体体积积和和梯梯形形的的面面积积等等问问题题显显然然也也可可以以用用函函数解决。数解决。带参数的宏和函数在形式上有相似的地方,但是它们有许多不同点:带参数的宏和函数在形式上有相似的地方,但是它们有许多不同点:(1)(1)宏宏展展开开是是在在编编译译时时进进行行的的,不不占占用用程程序序运运行行时时间间,在在展展开开时时并并不不分分配配内内存存单单元元,即即使使
16、是是带带参参数数的的宏宏也也不不分分配配内内存存单单元元;而而函函数数调调用用则则是是在在程程序序运运行时进行处理的,占用程序运行时间,要为形参分配临时的内存单元。行时进行处理的,占用程序运行时间,要为形参分配临时的内存单元。(2)(2)宏宏展展开开只只是是替替换换;而而函函数数调调用用时时,要要计计算算实实参参表表达达式式的的值值后后传传递递给给形形参参,不不是是替替换换。函函数数调调用用时时存存在在着着从从实实参参向向形形参参传传递递数数据据的的过过程程,而而使使用用带带参数的宏,也不存在传递数据的过程。参数的宏,也不存在传递数据的过程。(3)(3)宏宏名名以以及及它它的的参参数数都都不不
17、存存在在类类型型问问题题,展展开开时时用用指指定定的的字字符符串串替替换换即即可。而函数中的实参和形参都要定义类型。可。而函数中的实参和形参都要定义类型。(4)宏展开后对源程序长度有影响,而函数调用对源程序长度无影响。宏展开后对源程序长度有影响,而函数调用对源程序长度无影响。有些问题,用宏和函数都可以,如下例:有些问题,用宏和函数都可以,如下例:用函数:用函数:max(int x,int y)return(xy)?x:y;main()int a,b,c,d,t;t=max(a+b,c+d);用宏用宏:#define MAX(x,y)(x)(y)?(x):(y)main()int a,b,c,d
18、,t;t=MAX(a+b,c+d);赋值语句展开后为赋值语句展开后为 t=(a+b)(c+d)?(a+b):(c+d);8.2 “文件包含”处理 l C语语言言提提供供了了#include命命令令用用来来实实现现“文文件件包包含含”的的操操作作。作用是将一个源文件的全部内容包含进另一个源文件中来。作用是将一个源文件的全部内容包含进另一个源文件中来。l 被被包包含含的的文文件件可可以以是是C语语言言源源文文件件、库库函函数数头头文文件件等等。因因为为#include命命令令行行通通常常都都放放在在文文件件的的开开头头,所所以以这这些些被被包包含含的的文文件件通通常常被被称称为为“标标题题文文件件
19、”或或“头头文文件件”,常常以以“.h”(h为为head的的缩缩写写)为为文文件件的的扩扩展展名名。当当然然也也可可以以用用其其他他文文件件扩扩展展名名,但无论用什么扩展名,这个被包含文件必须是文本文件。但无论用什么扩展名,这个被包含文件必须是文本文件。l C集集成成环环境境为为用用户户提提供供了了很很多多库库函函数数,每每一一个个库库函函数数都都有有自自己己对对应应的的头头文文件件,在在C语语言言库库函函数数与与用用户户程程序序之之间间进进行行信信息息通通信信时时,要要使使用用一一些些库库函函数数中中定定义义的的数数据据和和变变量量,在在使使用用某某一一库库函函数数时时,都都要要在在程程序序
20、中中使使用用#include命命令令将将该该函函数数所所对对应应的的头头文件包含进来文件包含进来,否则,程序在编译时报错。,否则,程序在编译时报错。文件包含的使用格式为:文件包含的使用格式为:include include “文件名文件名”或或 include include 文件名文件名 其中的其中的“文件名文件名”和和的区别是:当使的区别是:当使用用“文件名文件名”形式时,预处理程序首先检索当前形式时,预处理程序首先检索当前文件目录是否有该文件,如果没有,再检索文件目录是否有该文件,如果没有,再检索C编译编译系统中指定的目录;而使用系统中指定的目录;而使用形式时,预形式时,预处理程序直接检
21、索处理程序直接检索C编译系统指定的目录。使用编译系统指定的目录。使用“”“”时,格式文件包含名可加路径。时,格式文件包含名可加路径。例如:例如:#include“d:tcincludestdio.h”常用的标准库头文件的扩展名都是常用的标准库头文件的扩展名都是h h,如:,如:#include /*#include /*标准输入输出函数文件标准输入输出函数文件*/#include /*#include /*字符串函数文件字符串函数文件*/#include /*#include /*字符函数文件字符函数文件*/#include#include /*数学函数库文件数学函数库文件*/“文文件件包包含
22、含”命命令令可可以以节节省省程程序序设设计计人人员员的的劳劳动动。例例如如,可可以以将将经经常常使使用用一一组组固固定定的的符符号号常常量量(g=9.81(g=9.81,pi=3.1415926 pi=3.1415926,e=2.718e=2.718等等等等)用用宏宏定定义义命命令令组组成成一一个个文文件件,只只要要用用#include#include命命令令这个文件包含到自己所写的源文件中即可。这个文件包含到自己所写的源文件中即可。正正确确的的使使用用#include#include语语句句,将将会会减减少少不不必必要要的的重重复复工工作作,提提高高编编程程效效率率。特特别别是是在在一一个个
23、软软件件开开发发小小组组共共同同协协作作开开发发大大型型软软件件时时,includeinclude文文件件十十分分有有用用,利利用用它它可可以以定定义义程程序序中中共共同同的的常常量量、函数原型、宏等,这样可以便于修改且不易出错。函数原型、宏等,这样可以便于修改且不易出错。例例8.5 编制如下内容的被包含文件,将其拷贝到编制如下内容的被包含文件,将其拷贝到C C语言目录中。该文件名为语言目录中。该文件名为bj.hbj.h。#define START#define START#define OK#define OK#define MAX(x,y)xy?x:y#define MAX(x,y)xy?
24、x:y编写另一程序编写另一程序file.cfile.c,内容如下:,内容如下:#include#include#include “bj.h”#include “bj.h”int main()int main()START START double x=500.0,y=100.0;long lx=25,ly=37;double x=500.0,y=100.0;long lx=25,ly=37;printf(“double printf(“double MAX=%lfn”,MAX=%lfn”,MAX(x,y);MAX(x,y);printf(“long printf(“long MAX=%ldn”
25、,MAX=%ldn”,MAX(lx,ly);MAX(lx,ly);return 0;return 0;OK OK 注注意意:在在编编译译时时并并不不是是作作为为两两个个文文件件进进行行连连接接的的,而而是作为一个源程序编译,得到一个目标是作为一个源程序编译,得到一个目标(.obj)(.obj)文件。文件。执行程序执行程序file.cfile.c,结果显示如下:,结果显示如下:double MAX=500.000000double MAX=500.000000long MAX=37long MAX=37说明:说明:(1)(1)如如果果要要包包含含n n个个文文件件,必必须须用用n n个个incl
26、udeinclude命命令令。即即一一个个includeinclude命令只能指定一个被包含文件。命令只能指定一个被包含文件。(2)(2)假假设设“wj1.c”“wj1.c”、“wj2.c”“wj2.c”、“wj3.c”“wj3.c”是是三三个个不不同同的的文文件,若在件,若在“wj1.c”“wj1.c”有如下两行命令:有如下两行命令:#include#include#include#include 则则在在文文件件“wj1.c”“wj1.c”中中可可以以用用“wj2.c”“wj2.c”和和“wj3.c”“wj3.c”的的内内容容,在在文文 件件“wj2.c”“wj2.c”中中 可可 以以 用
27、用“wj3.c”“wj3.c”的的 内内 容容,不不 必必 在在 文文 件件“wj2.c”“wj2.c”中再使用中再使用“#include#include ”命令。命令。若若在在“wj1.c”“wj1.c”中中只只有有“#include“#include ”命命令令,而而“wj1.c”“wj1.c”中中又又要要使使用用“wj3.c”“wj3.c”的的内内容容,也也可可以以让让“wj2.c”“wj2.c”中中出现出现“#include ”“#include ”命令。即文件包含可以嵌套使用。命令。即文件包含可以嵌套使用。l例例8.4l/*file.c*/l#include l#include “m
28、yfile.txt”lint main()l fun();l return 0;llmyfile.txt文本文件内容如下文本文件内容如下lvoid fun()lchar c;l if(c=getchar()!=n)l putchar(c);l fun();l 在编译在编译file.c时,预处时,预处理过程中用理过程中用myfile.txt文件文件的文本替换的文本替换file.c中的中的#include“myfile.txt”,因此本例程序功能是接因此本例程序功能是接受用户的按键,直到按回受用户的按键,直到按回车键为止,然后将字符序车键为止,然后将字符序列显示出来。列显示出来。8.3 条件编译条
29、件编译 有有时时希希望望当当满满足足某某条条件件时时对对一一组组语语句句进进行行编编译译,而而当当条条件件不不满满足足时时则则编编译译另另一一组组语语句句,使使得得同同一一个个源源程程序序在在不不同同的的编编译译条条件件下下能能够够产产生生不不同同的的目目标标代代码文件。这就是码文件。这就是“条件编译条件编译”。条件编译命令有以下条件编译命令有以下3种形式:种形式:1、#ifdef 标识符标识符 程序段程序段1#else 程序段程序段2#endif 作用:当标识符已经被定义过作用:当标识符已经被定义过(一般是用一般是用define命令定义命令定义),则对程则对程序段序段1进行编译;否则编译程序
30、段进行编译;否则编译程序段2。其中(其中(#else 程序段程序段2)可)可以没有。以没有。作用:作用:若标识符未被若标识符未被定义,则编译程序段定义,则编译程序段1;否则编译程序段否则编译程序段2。2、#ifndef 标识符 程序段1#else 程序段2#endif3、#if 表达式 程序段1#else 程序段2#endif 作用:当指定的表达式作用:当指定的表达式值为真(非零)时编译程序值为真(非零)时编译程序段段1;否则编译程序段;否则编译程序段2。#include#define TERM 0 int main()int i,a10;float s=0,t=1;for(i=0;i10;i
31、+)scanf(“%d”,&ai);#if TERM for(i=0;i10;i+)t=t*ai;printf(%f,t);#else for(i=0;i10;i+)s=s+ai;printf(%f,s);#endif return 0;执行程序,若输入如下执行程序,若输入如下10个数:个数:1 2 3 4 5 6 7 8 9 10输出结果为:输出结果为:55.000000若将程序中的若将程序中的“#define TERM 0”改为改为“#define TERM 1”,同样输入上面的同样输入上面的10个数,程序运个数,程序运行的输出结果为:行的输出结果为:3628800.000000 例例8.5 输入输入10个整数,根据需要设置条件编译,能够求个整数,根据需要设置条件编译,能够求10个个整数的和,或求整数的和,或求10个整数的积。个整数的积。8.4 本章小结本章小结l本章介绍了宏定义的两种形式,本章介绍了宏定义的两种形式,介绍了文件包含的使用方法,介介绍了文件包含的使用方法,介绍了条件编译的概念。绍了条件编译的概念。