C语言程序设计第10章 预处理命令_第1页
C语言程序设计第10章 预处理命令_第2页
C语言程序设计第10章 预处理命令_第3页
C语言程序设计第10章 预处理命令_第4页
C语言程序设计第10章 预处理命令_第5页
已阅读5页,还剩40页未读, 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

10预处理命令第章在前面各章中,我们已多次使用过以“#”号开头的预处理命令,例如,#include命令,#define命令等。几乎每个C程序都会包含预处理命令,它是C程序的重要组成部分。合理地使用预处理命令可以使程序便于阅读、修改、移植和调试,也有利于模块化程序设计。本章首先介绍了宏定义命令,然后介绍了文件包含命令,最后介绍了条件编译命令。学习目标

掌握宏定义相关内容

掌握文件包含命令的使用

了解条件编译命令的使用宏定义10.1文件包含命令10.2条件编译命令10.3常见错误分析10.4目录CONTENTSPART10.1宏定义宏定义是预处理命令的一种,它提供了一种可以替换源代码中字符串的机制。根据宏定义中是否有参数,可以将宏定义分为不带参数的宏定义和带参数的宏定义两种,下面分别进行介绍。10.1宏定义10.1.1不带参数的宏定义不带参数的宏定义比较简单,就是用一个指定的标识符来代表一个字符串。其一般形式为:#define标识符字符串其中的“#”表示这是一条预处理命令;“define”为宏定义命令;“标识符”就是“宏名”;“字符串”可以是常数、表达式、格式字符串等。例如:#definePI3.1415926它的作用是用指定标识符PI代替常量“3.1415926”。在编写源程序时,所有的3.1415926都可由PI代替,在进行预处理时,系统会将程序中所有在该命令以后出现的PI都用3.1415926代替。我们把在预处理时将宏名替换成字符串的过程称为“宏展开”。10.1宏定义10.1.1不带参数的宏定义对于宏定义,还要说明以下几点:1为了与变量相区别,宏名习惯上用大写字母表示,但也允许使用小写字母。2宏定义只是用宏名代替一个字符串,也就是只作简单的置换,不作正确性检查。例如,在上述宏定义中,将数字“1”错写成字母“l”,即“#definePI3.l4l5926”,在预处理时也照样把字母“l”代入。预处理时不作任何语法检查,只有对已被宏展开后的源程序进行编译时才会发现语法错误并报错。10.1宏定义10.1.1不带参数的宏定义5宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开时,由预处理程序层层代换。4宏定义必须写在函数之外,默认其作用域为宏定义命令起到源程序结束。3宏定义不是C语句,不需要在行末加分号。如果加上分号,则连同分号一起置换。10.1宏定义10.1.1不带参数的宏定义在宏定义中引用已定义的宏名。#include<stdio.h>#definePI3.14#defineR4#defineL2*PI*R /*PI和R是已定义的宏名*/intmain(){ printf("L=%f\n",L); /*在宏展开后为:printf("%f",2*3.14*4);*/ return0;}10.1宏定义10.1.1不带参数的宏定义程序运行结果如图所示。10.1宏定义10.1.1不带参数的宏定义7宏定义与变量定义的含义不同,宏定义不分配内存,变量定义分配内存。千万不要把宏名当做变量名使用。6对程序中用双引号括起来的字符串内的字符,即使与宏名相同,也不进行置换。例如,例10-1中的printf函数内有两个“L”字符,其中一个在双引号内的,在程序运行时没有被宏置换。10.1宏定义10.1.2带参数的宏定义C语言允许宏带有参数,带参数的宏定义一般形式为:#define宏名(参数表)字符串在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。带参数的宏定义不是进行简单的字符串替换,还要进行参数替换,即用实参去替换形参。带参宏调用的一般形式为:宏名(实参表);用带参数的宏求矩形面积。10.1宏定义10.1.2带参数的宏定义#include<stdio.h>#defineS(a,b)a*b /*定义带参数的宏*/intmain(){ intm=3,n=4,area; area=S(m,n); /*宏调用,等价于area=m*n;*/ printf("area=%d\n",area); return0;}10.1宏定义10.1.2带参数的宏定义程序运行结果如图所示。10.1宏定义10.1.2带参数的宏定义以上定义矩形面积S,a和b为边长。在程序中用了“S(m,n)”,把m和n分别代替宏定义中的形式参数a和b,即赋值语句置换为“area=m*n;”。置换的方法是:按#define命令行中指定的字符串从左到右进行置换,用实参置换形参,保留非参数字符,如图所示。10.1宏定义10.1.2带参数的宏定义用带参数的宏求两数中较大值。#include<stdio.h>#defineMAX(a,b)(a>b)?a:b /*定义带参数的宏*/intmain(){ intx,y,max; printf("inputtwonumbers:"); scanf("%d,%d",&x,&y); max=MAX(x,y); /*宏调用,等价于max=(x>y)?x:y*/ printf("max=%d\n",max); return0;}10.1宏定义10.1.2带参数的宏定义程序运行结果如图所示。10.1宏定义10.1.2带参数的宏定义对于带参的宏定义,有以下几点需要说明:1在宏定义时,宏名与带参数的括号之间不能有空格,否则会将空格以后的字符都作为替代字符串的一部分。例如,#defineS(a,b)a*b /*S与(a,b)之间有空格*/系统会认为S是符号常量(不带参数的宏名),它代表字符串“(a,b)a*b”。2对带参数的宏的展开,只是将语句中的宏名后面括号内的实参字符串代替#define命令行中的形参。因此,宏定义时参数应加括号,同时,宏扩展时应使用括号来保护表达式中低优先级的操作符,以确保达到想要的效果。10.1宏定义10.1.2带参数的宏定义两数的乘法加法混合运算。#include<stdio.h>#defineMIX(a,b)((a)*(b)-(a)) /*定义带参数的宏*/intmain(){ intx,y,m; printf("inputtwonumbers:"); scanf("%d,%d",&x,&y); m=5*MIX(x,x+y); /*等价于5*((x)*(x+y)-(x))*/ printf("m=%d\n",m); return0;}10.1宏定义10.1.2带参数的宏定义程序运行结果如图所示。10.1宏定义10.1.2带参数的宏定义在程序中,带参数的宏的展开“5*MIX(x,x+y)”等价于5*((x)*(x+y)-(x)),因此,当输入x等于2,y等于3时,表示求5*((2)*(2+3)-(2))的值(40)。如果宏定义时参数或宏展开没有括号,都得不到想要的结果。例如,将宏定义改成“#defineMIX(a,b)a*b-a”,同样计算“m=5*MIX(x,x+y);”的值应为5*x*x+y-x,当输入x等于2,y等于3时,结果为21。3带参的宏和带参函数很相似,但本质上是不同的。①函数调用是在程序运行时进行,为形参分配临时的内存单元。而宏置换则是在预处理阶段进行,在置换时并不分配内存单元。在带参宏定义中,形式参数不分配内存单元,因而不必作类型声明。10.1宏定义10.1.2带参数的宏定义②调用函数时,先求出实参表达式的值,然后代入形参。而使用带参数的宏只是进行简单的字符替换。例如,例10-4中“m=5*MIX(x,x+y);”,在宏置换时并不求“x+y”的值,而只将实参字符“x+y”代替形参b。③函数只有一个返回值,而利用宏可以得到多个值。④宏展开会使源程序变长,而函数调用不会。⑤宏展开不占运行时间,只占预处理时间,而函数调用占用运行时间(分配内存、保留现场、值传递、返回值)。10.1宏定义10.1.3撤销宏定义命令撤销已定义的宏。#include<stdio.h>#definePI3.14159 /*利用宏定义定义符号常量PI*/voidfunction(); /*函数声明*/intmain(){ printf("%f\n",PI); /*输出PI的值*/ function(); /*函数调用*/ return0;}#undefPI /*撤销宏定义*/voidfunction() /*自定义函数*/{ printf("%f\n",PI); /*输出PI的值*/}宏定义命令#define通常写在一个文件的起始位置,这样一来,宏定义在整个文件范围内都是有效的。当然,也可以用命令#undef撤消已定义的宏,终止该宏定义的作用域。10.1宏定义10.1.3撤销宏定义命令程序编译时提示出错,错误信息如图所示。由于程序中“#undefPI”撤销了宏定义,因此,PI只在main函数中有效,在后面的function函数中无效,当function函数中输出PI的值时系统提示错误。若无“#undefPI”,则PI在main函数、function函数中都有效。PART10.2文件包含命令10.2文件包含命令几乎所有的程序都会用到文件包含命令,如:#include<stdio.h>文件包含是指一个源文件可以将另一个源文件的全部内容包含进来,即将另外的文件内容包含到本文件之中,插入到当前的位置。其一般形式为:#include<文件名> /*搜索系统头文件所在的目录(或多个目录)*/或#include"文件名" /*先搜索当前目录,然后搜索系统头文件所在的目录(或多个目录)*/在程序设计中,文件包含是很有用的。一个大的程序可以分为多个模块,由多个程序员分别编写。有些公用的符号常量或宏定义等可单独组成一个文件,在其他文件的开头用包含命令包含该文件即可。这样,可避免在每个文件开头都书写公用量,从而节省时间,并减少出错。10.2文件包含命令将例10-3的宏定义做成头文件,把它包含在用户程序中。(1)将宏定义做成头文件“10-6.h”,包含以下代码。#defineMAX(a,b)(a>b)?a:b /*定义带参数的宏*/(2)编写主文件10-6.c,包含以下代码。#include<stdio.h>#include"10-6.h" /*包含文件10-6.h*/intmain(){ intx,y,max; printf("inputtwonumbers:"); scanf("%d,%d",&x,&y); max=MAX(x,y); /*宏调用,等价于max=(x>y)?x:y*/ printf("max=%d\n",max); return0;}10.2文件包含命令编译运行10-6.c文件,程序运行结果如图所示。10.2文件包含命令在预处理时将文件“10-6.h”的内容包含到主文件“10-6.c”中(取代#include命令),得到一个新的源程序,编译系统对其进行编译,得到一个目标文件。这种常用于文件头部的被包含的文件称为“头文件”,常以“.h”为后缀(h为header的缩写),如“10-6.h”文件。当然,不用“.h”为后缀,而用“.c”为后缀或者没有后缀也是可以的,但用“.h”作后缀更能表示此文件的性质。

名师点睛(l)一个include命令只能指定一个被包含文件,若有多个文件要包含,则需用多个include命令。(2)文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。PART10.3条件编译命令10.3条件编译命令一般情况下,源程序中所有的行都参加编译。但有时希望其中一部分内容只在满足一定条件下才进行编译,即对一部分内容指定编译条件,这就是“条件编译”。条件编译有三种形式,下面分别进行介绍。#ifdef形式1#ifdef标识符 程序段1#else 程序段2#endif其作用是:如果标识符已被#define命令定义,则对程序段1进行编译;否则对程序段2进行编译。如果没有程序段2,此形式也可以写为:#ifdef标识符 程序段#endif10.3条件编译命令#include<stdio.h>#defineDEBUGok /*宏定义*/intmain(){#ifdefDEBUG /*如果DEBUG已经被定义*/ printf("yes\n");#else /*如果DEBUG没有被定义*/ printf("no\n");#endif return0;}条件编译,#ifdef的应用。10.3条件编译命令程序运行结果如图所示。在程序的第一行宏定义中,定义DEBUG表示字符串“ok”,其实可以为任何字符串,甚至不给出字符串,写为“#defineDEBUG”,也具有同样的意义。只有取消程序的第一行才会去编译第二个printf语句。10.3条件编译命令#ifndef形式2#ifndef标识符 程序段1#else 程序段2#endif与第一种形式的区别是将“ifdef”改为了“ifndef”。它的作用是,如果标识符未被#define命令定义,则对程序段1进行编译,否则对程序段2进行编译。这与第一种形式的功能正好相反。10.3条件编译命令#if形式3#if常量表达式 程序段1#else 程序段2#endif其作用是:判断常量表达式的值,当常量表达式的值为真(非0),则对程序段1进行编译,否则对程序段2进行编译。10.3条件编译命令#include<stdio.h>#defineR1 /*用宏定义定义符号常量R*/intmain(){ floatr,s; printf("inputanumber:"); scanf("%f",&r);#ifR /*如果R为非0值,则计算s的值并输出*/ s=3.14159*r*r; printf("areaofroundis:%f\n",s);#else /*如果R为0,则计算s的值并输出*/ s=r*r; printf("areaofsquareis:%f\n",s);#endif return0;}条件编译,#if的应用。10.3条件编译命令程序运行结果如图所示。在程序开始的宏定义中,定义R为1,因此在条件编译时,常量表达式的值为真,故计算并输出圆面积。PART10.4常见错误分析10.4常见错误分析宏定义时缺少“#”1#include<stdio.h>definePI3.14159 /*缺少“#”号*/intmain(){ printf("%f\n",PI); return0;}宏定义必须以“#”开头,如果缺少“#”,编译器就会报错。例如:10.4常见错误分析编译错误信息如图所示。原因是“define”前缺少标识符“#”号,只要添加了“#”号,此程序就能正确编译。10.4常见错误分析宏定义后面多分号2#include<stdio.h>#definePI3.14159; /*行末多了分号*/intmain(){ printf("%f\n",PI); return0;}宏定义不是C语句,不需

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论