《《预处理命令 》PPT课件.ppt》由会员分享,可在线阅读,更多相关《《预处理命令 》PPT课件.ppt(21页珍藏版)》请在三一办公上搜索。
1、第6.5章:预处理命令,学习的意义,C语言的一个重要特征是它的预处理功能。我们知道,一个高级语言源程序在计算机上运行,必须先用编译程序将其翻译为机器语言。编译包括词法分析、语法分析、代码生成、代码优化等步骤,有时在编译之前还要做某些预处理工作,如去掉注释,变换格式等。C语言允许在源程序中包含预处理命令,在正式编译之前(词法分析之前)系统先对这些命令进行“预处理”,然后整个源程序再进行通常的编译处理。从语法上讲,这些预处理命令不是C语言的一部分,但使用它们却扩展了C语言程序设计的环境,可以简化程序开发过程,提高程序的可读性,也更有利于移植和调试C语言程序。本章主要介绍宏定义、文件包括和条件编译等
2、预处理命令。,学习的意义,源程序生成执行文件的过程:,#include#define PI 3.14159void main()float r=4;printf(“s=%fn”,PI*r*r);,本章讨论之重点!,学习目标,学习内容,预处理命令简介宏定义 不带参数的宏定义 带参数的宏定义文件包括条件编译本章小结,掌握#include、#define、#if、#ifdef、#else、#ifndef和#endif等命令的用法;掌握宏定义和宏替换的一般方法;掌握包含文件的处理方法;了解条件编译的作用和实现方法。,6.5.1 预处理命令简介,预处理命令:C源程序中以#开头、以换行符结尾的行,种类:,
3、宏定义#define、#undef 文件包含#include 条件编译#if、#ifdef、#else、#elif、#endif等 其他#line、#error、#program等,本章主要讨论的内容!,格式:,“#”开头 占单独书写行 语句尾不加分号,6.5.2 宏定义,宏定义分为两种:不带参数的宏定义和带参数的宏定义。,1、不带参数的宏定义,一般形式,#define 标识符 单词串,指令名称,宏名,被定义代表后面的单词串,宏体,是宏的内容文本,可缺省,表示宏名定义过或取消宏体,功能,用指定标识符(宏名)代替字符序列(宏体),如#define YES 1#define NO 0#define
4、 PI 3.1415926#define OUT printf(“Hello,World”);,#define SIZE 10#define INT_STR%dvoid main()int aSIZE,i;for(i=0;i=0;i-)printf(INT_STR,ai);,void main()int a10,i;for(i=0;i=0;i-)printf(%d,ai);,注意:宏替换时仅仅是将源程序中与宏名相同的标识符替换成宏的内容文本,并不对宏的内容文本做任何处理。,宏定义注意事项,C程序员通常用大写字母来定义宏名,以便与变量名区别。,如:#define PI 3.14159,宏定义的位
5、置任意,但一般放在函数外面。,宏定义时,如果单词串太长,需要写多行,可以在行尾使用反斜线“”续行符,例如:#define LONG_STRING this is a very long string that isused as an example,宏名的作用域是从#define定义之后直到该宏定义所在文件结束,#undef可终止宏名作用域,#undef 标识符,宏定义可以嵌套定义,但不能递归定义,#define R 2.0#define PI 3.14159#define L 2*PI*R()#define S PI*R*R(),#define M M+10(),程序中字符串常量即双引号中
6、的字符,不作为宏进行宏替换操作,#define XYZ this is a test printf(XYZ);输出:XYZ,而不是:this is a test。,宏定义注意事项,宏定义一般以换行结束,不要用分号结束,以免引起不必要的错误,#define PI 3.14;a=PI*2*2;,a=3.14;*2*2;,错误!,宏可以被重复定义。,在定义宏时,如果宏是一个表达式,那么一定要将这个表达式用()括起来,否则可能会引起非预期的结果。,#define NUM1 10#define NUM2 20#define NUM NUM1+NUM2 void main()int a=2,b=3;a*=
7、NUM;b=b*NUM;printf(a=%d,b=%dn,a,b);,void main()int a=2,b=3;a*=10+20;b=b*10+20;printf(a=%d,b=%dn,a,b);,输出结果:a=60,b=50,输出结果:a=60,b=90,2、带参数的宏定义,一般形式,#define 标识符(参数列表)单词串,参数表由一个或多个参数构成,参数只有参数名,没有数据类型符,参数之间用逗号隔开,参数名必须是合法的标识符,通常会引用宏的参数,例:#define S(a,b)a*b.area=S(3,2);宏展开:area=3*2;,宏展开:形参用实参换,其它字符保留宏体及各形参
8、外一般应加括号(),不能加空格,例#define S(r)PI*r*r相当于定义了不带参宏S,代表字符串“(r)PI*r*r”,例#define POWER(x)x*x x=4;y=6;z=POWER(x+y);宏展开:z=x+y*x+y;一般写成:#define POWER(x)(x)*(x)宏展开:z=(x+y)*(x+y);,#define MAX(x,y)(x)(y)?(x):(y).void main()int a,b,c,d,t;.t=MAX(a+b,c+d);宏展开:t=(a+b)(c+d)?(a+b):(c+d);,int max(int x,int y)return(x y?
9、x:y);void main()int a,b,c,d,t;.t=max(a+b,c+d);,【例】用宏定义和函数实现同样的功能,带参的宏与函数区别,6.5.3 文件包含,处理过程,功能 一个源文件可将另一个源文件的内容全部包含进来,一般形式,#define 或#define“包含文件名”,预编译时,用被包含文件的内容取代该预处理命令,再对“包含”后的文件作一个源文件编译,:直接到系统指定的“文件包含目录”去查找被包含的文件,“”:系统首先到当前目录下查找被包含文件,如果没找到,再到系统指定的“文件包含目录”去查找。,文件包含举例:,#include head.h#include func.c
10、pp void main()int a,b,c;a=getnum();b=getnum();c=max(max(a,b),NUM);printf(MAX=%dn,c);,(stdio.h文件中的内容)#define NUM 10 int max(int x,int y)return(x y?x:y);int getnum()int a;scanf(%d,文件包含的优点:,一个大程序,通常分为多个模块,并由多个程序员分别编程。有了文件包含处理功能,就可以将多个模块共用的数据(如符号常量和数据结构)或函数,集中到一个单独的文件中(如上例中的文件head.h和func.cpp)。这样,凡是要使用其中
11、数据或调用其中函数的程序员,只要使用文件包含处理功能,将所需文件包含进来即可,不必再重复定义它们,从而减少重复劳动。,文件包含的几点说明,常用在文件头部的被包含文件,称为“标题文件”或“头部文件”,常以.h(head)作为后缀,简称头文件。在头文件中,除可包含宏定义外,还可包含外部变量定义、结构类型定义等。一条包含命令,只能指定一个被包含文件。如果要包含n个文件,则要用n条包含命令。文件包含可以嵌套,即被包含文件中又包含另一个文件。,6.5.4 条件编译,根据一定的条件去编译源文件的不同部分,这就是条件编译。,1、#if#endif形式,格式:,#if 条件1 程序段1#elif 条件2 程序
12、段2#else 程序段n#endif,常量表达式。通常会用到宏名,条件可以不加括号“()”,#elif和#else可以没有,#endif必须存在,它是#if命令的结尾,如果条件1为真就编译程序段1,否则如果条件2为真就编译程序段2,如果各条件都不为真就编译程序段n。,作用:,#if和#elif常常与defined命令配合使用,defined命令的格式为:,defined(宏名)或 defined 宏名,功能:判断某个宏是否已经定义,如果已经定义,defined命令返回1,否则返回0。Defined命令只能与#if或#elif配合使用,不能单独使用。,例如:#if defined(USA)的含义
13、是“如果定义了宏USA”。,例:下面的程序利用ACTIVE_COUNTRY定义货币的名称,#define USA 0#define ENGLAND 1#define FRANCE 2#define ACTIVE_COUNTRY USA#if ACTIVE_COUNTRY=USA char*currency=“dollar”;/有效#elif ACTIVE_COUNTRY=ENGLAND char*currency=pound;#else char*currency=france;#endif void main()float price1,price2,sumprice;scanf(%f%f,
14、char*currency=“dollar”;void main()float price1,price2,sumprice;scanf(%f%f,2、#ifdef#endif形式,格式:,#ifdef 宏名 程序段1#else 程序段2#endif,等价于“#if defined(宏名)”,在#ifdef和#else之间可以加多个#elif命令,如果宏名已被#define行定义,则编译程序段1,否则编译程序段2,作用:,#define INTEGER#ifdef INTEGER int add(int x,int y)/有效 return(x+y);#else float add(float
15、 x,float y)return(x+y);#endif void main()#ifdef INTEGER int a,b,c;/有效 scanf(%d%d,a,b);printf(a+b=%dn,add(a,b);#else float a,b,c;scanf(%f%f,a,b);printf(a+b=%fn,add(a,b);#endif,int add(int x,int y)/有效 return(x+y);void main()int a,b,c;/有效 scanf(%d%d,a,b);printf(a+b=%dn,add(a,b);,3、#ifndef#endif形式,格式:,#
16、ifndef 宏名 程序段1#else 程序段2#endif,如果宏名没被#define行定义,则编译程序段1,否则编译程序段2,作用:,条件编译与分支语句二者之间的差别:条件编译是在预编译时处理;而条件语句则是在程序运行时处理。条件编译中的条件不可以包含变量名,只能是常量表达式(通常包含宏名),可以不加括号;而条件语句中的条件是条件表达式,可以包含变量或函数等,并且必须加括号。,例如:#define N 10int NUM=10;#if NUM=10#endif,条件编译与分支语句二者之间的差别:条件编译是将满足编译条件的程序代码进行编译生成目标代码,不满足编译条件的程序代码将不进行编译;而
17、分支语句则是不管满足条件的代码,还是不满足条件的代码,都要编译生成目标代码(包括分支语句本身),所以如果用条件语句来代替条件编译命令,程序的目标代码将变长 条件编译命令可以放在所有函数的外部,也可以放在某函数的内部;但分支语句只能出现在某函数内部。,使用条件编译的原因:,便于程序的移植,#ifdef TURBOC/Turbo C独有的内容#endif#ifdef BORLANDC/Borland C独有的内容#endif#ifdef VISUALC/Visual C独有的内容#endif,如果希望这个程序在Borland C环境下编译运行,可在程序的前面写上:#define BORLANDC如
18、果希望生成Visual C版本,就在程序前面写上:#define VISUALC,便于程序调试,#define DEBUG#ifdef DEBUG printf();/临时结果#endif,本章小结:,C语言的预处理命令都是以“#”号开头,它们都不是C语言的语句,是在预编译时处理的。宏定义分为两种:不带参数的宏定义和带参数的宏定义,进行宏替换时,如果是不带参数的宏则只将与宏名相同的标识符都替换成宏的内容文本,如果是带参数的宏则首先将宏内容文本中的宏参数替换成实参文本,再将这样所得到的宏的实际内容文本替换源程序中的宏标识符。这样就形成了新的源程序,并且预编译器不对宏的内容文本做任何处理。宏定义时,末尾一般不要加分号。宏扩展的整体或参数一般要用括号括起来。文件包含的使用是编写C语言程序中不可缺少的,我们在引用C语言库函数时要使用它;另外,我们也可以将平时积累的一些有用的自定义函数做成一个自定义函数库文件,要使用它们时只需采用文件包含将它们引用过来使用就行,这样就减少了编程的工作量。使用条件编译的主要原因一是便于程序移植,二是方便程序调试。,