资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,C,语言程序设计基础,太原理工大学计算机学院计算机基础部,第,1,章 引言,第,10,章 编译预处理,编译预处理,预处理由专门的预处理程序负责完成。,当对一个源文件进行编译前,系统将自动引用预处理程序对源程序中的预处理部分作处理,处理完毕自动进入对源程序的编译。中间不需要人为干预。,编译预处理是由编译系统中的预处理命令进行的,语言提供了多种预处理功能,如文件包含、宏定义、条件编译等。,编译预处理命令,编译预处理命令主要有三种,即:宏定义、文件包含、条件编译。,所有的编译预处理命令均以,#,符号开头,各占用一个单独的书写行,末尾不用分号作结束符。,编译预处理命令可以出现在程序的任何位置,其作用域是自出现的地方开始直到源程序的末尾。,10.1,宏定义命令,#define,10.2,文件包含命令,#include,10.3,条件编译,10.4,编译预处理程序举例,10.1,宏定义命令,#define,10.1.1,无参宏定义,10.1.2,有参宏定义,10.1.3,有参宏与函数的区别,10.1.4,宏定义的解除和重新定义宏,10.1.1,无参宏定义,1.,所谓无参宏就是宏名后不带任何参数。,其定义的格式为:,#define,宏名 字符串,(,或数值,),其中的“,#”,表示这是一条预处理命令,C,语言中凡是以“,#”,开头的命令都为预处理命令。“,define”,为宏定义命令。,2.,宏定义在使用中应注意以下几点:,(,1,)宏名的前后应有空格。,(,2,)宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名。,(,3,)宏定义命令其后不要跟分号。,(,4,)字符串(或数值)中如果出现运算符号,则要注意替换后的结果,通常可以在合适的位置加上括号。,【,例,10.1】,#include,stdio.h,#define N3+4/*,定义,N,来替代表达式,3+4*/,int,main(),int,x,y,;,x=2*N;/*,宏调用*,/,y=2*(N);/*,宏调用*,/,printf(x=%d y=%dn,x,y);,return 0;,程序的运行结果为:,x=10 y=14,分析:,本例中用字符串“,3+4”,代替,N,,因此第,5,行的语句执行时,,x,的值应该为,2*3+4,,结果为,10,,而不是,2*7=14,;而第,6,行的语句“,y=2*(N);”,加了小括号,所以,y,的值为,2*,(,3+4,),=14,。,因此在进行宏定义时必须十分注意,应保证在宏代换之后不发生错误。,(,5,)宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用,#,undef,命令。,例如:,#define PI 3.1415926,main(),#,undef,PI,hans,(),PI,只在,main,函数中有效,在函数,hans,中是无效的。,(,6,),C,语言规定,宏名如果出现在字符串常量中或者用双引号括起来的字符串内时,将不作为宏名处理,不对其进行宏替换。,【,例,10.2】,#include,stdio.h,#define PI 3.14159 /*,定义,PI,来替代,3.14159*/,int,main(),float,c,radius,=2.5;,printf(c,=2*PI*radius=%fn,2*PI*radius);/*,宏名位于双引号内不进行宏代换*,/,return 0;,程序的运行结果为:,c=2*PI*radius=15.707950,而不是:,c=2*3.14159*radius=15.707950,(,7,)宏定义允许嵌套,在宏定义的字符串(或数值)中可以使用已经定义的宏名。在宏展开时由预处理程序层层代换。,例如:,#define PI 3.14159,#define C 2*PI*radius /*,其中的,PI,是已定义的宏名*,/,printf(%f,C,);,在宏代换后变为:,printf(%f,2*3.14159*radius);,(,8,)习惯上宏名用大写字母表示,以便与变量区别。但也可以用小写字母,用大写字母不是规定,只是一种习惯。建议用大写字母表示宏名。,(,9,)可用宏定义表示数据类型,使书写方便。,(,10,)对“输出格式”作宏定义,可以减少书写麻烦。,【,例,10.3】,分析程序的运行结果。,#include stdio.h,#define P printf,#define D%d,#define F%fn,int,main(),int,a=5,c=8,e=11;,double b=3.8,d=9.7,f=21.08;,P(D,F,a,b,);,P(D,F,c,d,);,P(D,F,e,f,);,return 0;,该程序的运行结果为:,53.800000,89.700000,1121.080000,【,例,10.4】,编程实现:从输入的,15000,个整数中寻找并输出最大数和最小数。,分析:如果直接编一个这样的程序,每次调试程序时,都要连续输入,15000,个整数,调试工作量很大。为了解决这个问题,可以使用宏定义将整数的个数定义的小一点,比如定义为,8,,先调试程序,程序正确后,再将宏定义中的个数改为,15000,。,#include,stdio.h,#define N 4 /*,定义,N,替代,4*/,int,main(),int,aN,max,min,;,int,i;,printf(Please,enter%d number:,n,N,);,for(i,=0;i,N;i,+),scanf(%d,&ai,);/*,输入,N,个整数*,/,max=min=a0;,for(i,=1;imax)max=ai;,if(ai,y)?x:y,/*,有参宏定义*,/,int,main(),int,a,b,max,;,printf(Input,two numbers:);,scanf(%d%d,&a,&b,);,max=,MAX(a,b,);/*,宏调用*,/,printf(max,=%,dn,max,);,return 0;,程序的运行情况为:,Input two numbers:123-24,max=123,2.,使用带参的宏定义时需要注意以下几点:,(,1,)带参宏定义中,宏名和形参表之间不能有空格出现。例如下面的宏:,#define,MIN(a,b,)(a,b)?a:b,如果写成如下的形式:,#define MIN,(a,b)(a,b)?a:b,/*,代表空格*,/,则,C,语言将认为该宏没有参数,宏名,MIN,代表字符串,“,(,a,b,)(a,b)?a:b,”,这显然是错误的。,(,2,)在宏定义中的形参是标识符,而宏调用中的实参可以是常量、变量和表达式。,(,3,)在宏定义中,字符串内的形参通常要用括号括起来以避免出错。,【,例,10-6】,分析程序的运行结果。,#include,stdio.h,#define,V(x,)(x)*(x)*(x)/*,有参宏定义*,/,int,main(),int,a,volume,;,printf(Input,a number:);,scanf(%d,&a,);,volume=V(a+5);/*,宏调用,实参为表达式,a+5*/,printf(volume,=%,dn,volume,);,return 0;,程序运行的结果为:,Input a number:3,volume=512,分析:该程序中的宏在展开时,用,a+5,代换,x,,再用,(x)*(x)*(x),代换,V(x,),,得到如下语句:,volume=(a+5)*(a+5)*(a+5);,【,例,10-,7】,分析程序的运行结果。,#include stdio.h,#define V(x)x*x*x /*,有参宏定义*,/,int main(),int a,volume;,printf(Input a number:);,scanf(%d,volume=V(a+5);/*,宏调用,实参为表达式,a+5*/,printf(volume=%dn,volume);,return 0;,程序的运行情况为:,Input a number:3,volume=38,分析:该程序中的宏在展开时,用,a+5,代换,x,,再用,x*x*x,代换,V(x,),,得到如下语句:,volume=a+5*,a+5,*,a+5,;,【,例,10.8】,分析程序的运行结果。,#include stdio.h,#define V(x)(x)*(x)*(x)/*,有参宏定义*,/,int main(),int a,volume;,printf(Input a number:);,scanf(%d,volume=2560/V(a+5);/*,宏调用,实参为表达式,a+5*/,printf(volume=%dn,volume);,return 0;,程序的运行情况为:,Input a number:3,volume=20480,分析:该程序中的宏在展开时,用,a+5,代换,x,,再用,(x)*(x)*(x),代换,V(x,),,得到如下语句:,volume=2560/(a+5)*(a+5)*(a+5);,【,例,10.9】,分析程序的运行结果。,#include stdio.h,#define V(x),(,(x)*(x)*(x),),/*,有参宏定义*,/,int main(),int a,volume;,printf(Input a number:);,scanf(%d,volume=2560/V(a+5);/*,宏调用,实参为表达式,a+5*/,printf(volume=%dn,volume);,return 0;,程序的运行情况为:,Input a number:3,volume=5,分析:该程序中的宏在展开时,用,a+5,代换,x,,再用,(x)*(x)*(x),代换,V(x,),,得到如下语句:,volume=2560/(a+5)*(a+5)*(a+5);,(,4,)宏定义也可用来定义多个语句,在宏调用时,把这些语句又代换到源程序内。,【,例,10.10】,分析程序的运行结果。,#include,stdio.h,#define SSSV(s1,s2,s3,v)s1=l*w;s2=l*h;s3=w*,h;v,=w*l*h;/*,有参宏定义*,/,int main(),int l=3,w=4,h=5,sa,sb,sc,vv;,SSSV(sa,sb,sc,vv);/*,宏调用*,/,printf(sa=%d sb=%d sc=%d vv=%dn,sa,sb,sc,vv);,return 0;,程序的输出结果,:,sa=12sb=15sc=20vv=60,分析:,用宏名,SSSV,表示,4,个赋值语句,,4,个形参分别为,4,个赋值符左部的变量。在宏调用时,把,4,个语句展开并用实参代替形参。使计算结果送入实参之中。,10.1.3,宏替换与函数的区别,宏替换和函数调用的区别是:,(1),定义形式上不同,(2),处理时间上不同,(3),处理方式上不同,(4),时空的开销上不同,(5),类型的要求上不同,【,例,10.11】,比较下面试图输出整数,1,5,的平方的两个程序。,(,1,)采用函数的程序,#include,stdio.h,int,sq(int,x);,int,main(),int,i=1;,while(i,=5),printf(%d,sq(i,+);,return 0;,int,sq(int,x),return(x,*x);,程序的运行结果如下:,1 4 9 16 25,(,2,)采用有参宏定义的程序,#include,stdio.h,#define,SQ(x,)(x)*(x),int,main(),int,i=1;,while(i,=5),printf(%d,SQ
展开阅读全文