第九章 预处理命令
第9章预处理命令

宏定义也可以带参数,其一般形式为:
#define 宏名(参数表) 字符串 如:#define S(a,b) area=S(3,2); 定义宏名S代表矩形面积,参数a,b为边长。 宏展开过程: a*b
S(3,2)
a*b
3*2
9.2 “文件包含”处理 在一个源文件中将另一个源文件的内容包含进来。
文件包含指令的一般形式: #include 或 #include “文件名” <文件名>
宏名N等同于符号常量,可以作为数组的长度。
9.1 宏定义
例:定义一个宏名来代表一个计算公式。 #define PI 3.1415926 #define AREA PI*r*r #include <stdio.h> void main() { r=3,s; s=3.1415926*r*r; s=PI*r*r; s=AREA; printf(“\n %f”,s); } 注意:系统对宏定义的预处理是一个字符串的还原过 程。
Thanks
9.3 条件编译
例:条件编译可以提高C源程序的通用性
#ifdef COMPUTER_A #define INTEGER_SIZE 16 #else #define INTEGER_SIZE 32 #endif 如果在这组条件编译命令之前曾出现以下命令: #define COMPUTER_A 0 或 #define COMPUTER_A 只要COMPUTER_A定义过。
printf(“\n %f”,area); }
9.2 “文件包含”处理
f.c #include “f.h” #include <stdio.h> void main() { printf(“\n%f”,f1(3.0)); printf(“\n %f”,fac(10)); } float f1(float r) { return(PI*r*r); } float fac(int n) { int i; float s=1; for(i=1;i<=n;i++) s*=i; return(s); }
第9章 预处理命令

student.num, , student.sex,student.score);
#else NUM,则不显示*/
/* 如未定义标识符
printf("未定义标识符NUM\n");
#endif
return 0;
}
程序运行结果:
已定义标识符
NUM 学号:101101 姓名:张三 性别:男 成绩:82.5
【思考验证】在上例中,如果把宏定义成:#define VOLUME(y) ((AREA(x))*(y))结果会怎么样?它与宏 的嵌套定义有何不同?
9.3 条件编译
条件编译有三种形式,下面分别介绍: (1)第一种形式: #ifdef 标识符
程序段1 #else
程序段2 #endif 它的功能是,如果标识符已被#define命令定义过,则对程序段1进行 编译;否则对程序段2进行编译。如果没有程序段2(它为空),本格式 中的#else可以没有,即可以写为: #ifdef 标识符 程序段
printf("i+A=%d\n",i+A);
/*
第一个宏定义没有结束,A=100*/
printf("max=%d\n",max(i,j)); /*调用max()函数,函数体在第二个宏定 义之后*/
#undef A
int max(int a, int b)
#define A 10
{return a>b? a+A:b+A;}
源代码:
#include <stdio.h>
#define PI 3.1415926
#define AREA(x) (PI*(x)*(x))
第9章 预处理命令

#define PI 3.1415926 main() {float l,s,r,v; printf("input radius:"); scanf("%f",&r); /*输入圆的半径*/ l=2.0*PI*r; /*圆周长*/ s=PI*r*r; /*圆面积*/ v=4.0/3.0*PI*r*r*r; /* 球体积 */ printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n", l,s,v); }
宏与函数没有任何关系! 宏只是简单的字符的替代! 宏的处理是在通常编译之前,更是在程 序运行之前,与内存、函数的实参、形 参、函数返回值没什么关系。 可以把宏代换看成是系统帮我们去完成 源程序的编辑。
“文件包含”处理 一个源文件可以将另外一个源文件的全 部内容包含进来。 可以理解为:系统将另外一个源文件的 内容帮我们抄写到当前文件中,以便当 前文件在编译时使用另外源文件中的内 容。
printf(“L=%f,S=%f”,2*3.14*3.0,3.14*3.0*3.0);
带参数的宏定义 一般形式: #define 宏名(参数表)字符串 带参数的宏在展开时,不是进行简单的 字符串替换,而是进行参数替换。
#define S(a,b) a*b area=S(2,3);
#define S(r) PI*r*r area=S(a+b);
预编译
area=PI*a+b*a+b;
本来想用a,b的和做为半径,可是• • • • • • 系统不会去帮你加括号
怎么解决???
在定义时加括号 #define S(r) PI*(r)*(r) area=S(a+b);
第九章 预处理命令

#define R 3.0 #define PI 3.1415926 #define L 2*PI*R #define S PI*R*R main() {printf(“S=%f\n”,S);} #undef L #undef S void fun() {…}
#include <stdio.h> #define IN scanf #define OUT printf #define N 2 void main() {int i; char name[N][20]; long num[N]; OUT("Please input name and ID:\n"); for (i=0;i<N;i++) {IN("%s",name[i]); IN("%ld",&num[i]);} for (i=0;i<N;i++) {OUT("%s\t",name[i]); OUT("%ld\n",num[i]);} }
功能:当标识符在该条件 编译结构之前没有被# define定义过时,程序段 1被编译;否则,编译程 序段2
举例
#define debug main() {…… #ifdef debug printf(“x=%d,y=%d,z=%d\n”,x,y,z); #endif }
举例
#define inttag 1 main( ) {int ch; scanf(“%d”,ch); #if inttag printf(“%d”,ch); #else printf(“%c”,ch); #endif }
第九章 预处理命令
例如
#define squ(n) n*n
第9章 预处理命令

常整数表达式中只能出现预定义的常量标识符,或整
常数,或字符常数等。
计算机与通信工程学院 24
9.3 条件编译
2. # ifdef … #endif 形式
这种形式为: #ifdef <标识符> <程序段> #endif 其语义是:如果 <标识符> 用#define命令定义过,
计算机与通信工程学院 14
9.1 宏定义
(4) 有副作用的表达式 (如修改变量的值) 不应该传递给 宏,因为宏的参数可能会被计算多次而产生意想不 到的结果。例如 #define SQUARE(a) a*a 如 i=3,以++i 代替参数a,则被展开成 ++i*++i,本来想 求 4 的平方 (16) ,结果却得到 20 。 (5)用带参的宏可以代替某些简单的带参函数。例如, 可以用 #define CIRCLE_AREA(x) (PI*(x)*(x)) 去代替函数: float circlearea(float x) {return 3.14159* x*x ;}
计算机与通信工程学院 11
9.1 宏定义
9.1.2 带参数的宏
宏定义的第二种情况是宏名后面可以带有参数,因 而在宏值中也有相同的参数。 带参数宏定义的一般格式为:
#define <宏名> (<参数表>) <含有参数的字符序列>
如
#define S(x)
5* x
其中 S 为宏名, x 为参数, 5* x 是带参数的字符序列。
#include "f2.c"
而在文件 f2.c 中又有: #include <math.h> #include "f3.c" 则 file1 也把 f2.c 中包含的文件全部包含进来。
预处理命令

二、表演区 (一)什么是表演区 表演区以幼儿表演游戏为设计核心,通过道具吸引幼儿积极参加故事表 演、游戏等活动。 (二)表演区的环境布置与材料投放 表演区可以分为固定式和活动式表演区角两类。 固定式的表演区角是指在活动室内辟出一定区域,存放表演所需要的用 具。 活动式的表演区角则是根据表演需要,临时在走廊、门厅、过道或室外 等地方设置表演场所,便于及时放置和收拢。
第9章 预处理命令
• 9. 1 概述 • 9. 2 宏定义 • 9. 3 文件包含 • 9. 4 条件编译
9. 2 宏定义
• 9. 2. 1 无参宏定义
• 无参宏的宏名后不带参数。 • 其定义的一般形式为 • #define 标识符字符串 • 其中, #表示这是一条预处理命令; 凡是以#开头的指令均为预处理命
果果:“老师,一分钟是多久呢?” 教师:“就是一会儿,我一转身。” 贝贝:“我知道,最细的秒针走一圈,挺长的。” 佳佳:“一分钟就是我们从门口走到后面的窗子那里。” 教师:“一分钟能做什么?” 佳佳:“给花浇水。” 果果:“唱完一首歌。” 贝贝:“搬来一把椅子。”……
学习目标
1. 了解幼儿日常交谈的主要特点及指导要求。 2. 掌握语言区角的环境布置与材料投放要求,能科学地开展语言区角活 动的指导。 3. 学会设计听说游戏的玩法,并能评析幼儿园听说游戏。
上一页 下一页 返回
9. 2 宏定义
• 【例9 - 2】不作宏代换程序举例。
上一页 下一页 说明: • 虽然已定义宏名OK 表示100, 但在printf 语句中OK 被引号括起来, 因
此不作宏代换。 • 程序的运行结果为“OK”, 这表示把“OK” 当字符串处理。
上一页 下一页 返回
义时, 必须十分注意, 应保证在宏代换之后不发生错误。
第9章 预处理命令
(3) 宏定义是用宏名代替一个字符串,也就是作简单的置换,不 作正确性检查.如果写成 #define PI 3.l4l59 即把数字1写成小写字母l,预处理时也照样代入,不管含义是否 正确.也就是说预编译时不作任何语法检查.只有在编译已被宏 展开后的源程序时才会发现错误并报错. (4) 宏定义不是C语句,不必在行末加分号.如果加了分号则会连 分号一起进行置换.如: #define PI 3.1415926; area=PI*r*r; 经过宏展开后,该语句为 area=3.1415926;*r*r; 显然出现语法错误. (5) #define命令出现在程序中函数的外面,宏名的有效范围为定 义命令之后到本源文件结束.通常,#define命令写在文件开头, 函数之前,作为文件一部分,在此文件范围内有效.
西北师大数信学院信息系
(7) 在进行宏定义时,可以引用已定义的宏名,可以层层置换. 例9.2 #define R 3.0 #define PI 3.1415926 #define L 2*PI*R #define S PI*R*R main() { printf("L=%f\nS=%f\n",L,S); }
西北师大数信学院信息系
运行情况如下: input radius:4 l=25.1328 s=50.2655 v=150.7966 说明: (1) 宏名一般习惯用大写字母表示,以便与变量名相区别.但这并非 规定,也可用小写字母. (2) 使用宏名代替一个字符串,可以减少程序中重复书写某些字符串 的工作量.例如,如果不定义PI代表3.1415926,则在程序中要多处 出现3.1415926,不仅麻烦,而且容易写错(或敲错),用宏名代替, 简单不易出错,因为记住一个宏名(它的名字往往用容易理解的单词 表示)要比记住一个无规律的字符串容易,而且在读程序时能立即知 道它的含义,当需要改变某一个常量时,可以只改变#define命令行, 一改全改.例如,定义数组大小,可以用 #define array-size 1000 int array[array-size]; 先指定array-size代表常量1000,因此数组array大小为1000,如果 需要改变数组大小,只需改 #define行: #define array-size 500 使用宏定义,可以提高程序的通用性. 西北师大数信学院信息系
●第9章 预处理命令
⑥宏可以嵌套定义 如: #include <stdio.h> #define R 3.0 #define PI 3.14159 #define L 2*PI*R /*嵌套PI和R*/ #define S PI*R*R void main() { printf("L=%.4f,S=%.4f\n",L,S); } ⑦宏展开时,字符串常量中与宏名相同的字符不替换。 如: printf(“L=%.4f,S=%.4f\n”,L,S);编译后,展开生成: printf(“L=%.4f,S=%.4f\n”,2*3.14159*3.0,3.14159*3.0*3.0); 不替换
{ int a,b,c,d;
char string[ ]="CHINA"; a=1;b=2;c=3;d=4;
PR(D1,a);
PR(D2,a,b); PR(D3,a,b,c); PR(S,string); PR(NL); }
/*相当于printf("%d \n",a); */
/*相当于printf("%d %d \n",a,b); */ /*相当于printf("%d %d %d \n",a,b,c); */ /*相当于printf("%s",string); */ /*相当于printf("\n"); */
PR(D4,a,b,c,d); /*相当于printf("%d %d %d %d \n",a,b,c,d); */
缺点:程序的可读性降低。
13
§9.2文件包含处理
一.格式:#include <文件名> 或 #include "文件名" 注意: #与include之间无空格。 文件名要有扩展名。 二.功能:将指定的文件包含在本文件之中。 如:file1.c file2.c file1.c
第九章 预处理命令
#define N 3
#define Y(n) ((N+1)*n)
则执行语句z=2*(N+Y(5+1));后,z的值为
A出错B42C 48D54
2、以下程序运行后,输出结果是
#define PT 5.5
#define s(x) PT*x*x
main()
{int a=1,b=2;
printf(“%4.1f/n”,s(a+b));
8.对程序中用双引号括起来的字符串内的字符,即使与宏名相同也不进行置换。
9.宏定义是专门用于预处理命令的一个专用名词,它与定义变量的含义不同,只作字符替换,不分配内存空间。
9.1.2带参数的宏定义
#define宏名(参数表)字符串 如:#define S(a,b) a*b
说明:
1.对带参数的宏的展开只是将语句中的宏名后面括号内实参字符串代替#define命令行中的形参。
一般形式:#include“文件名”或#include<文件名>
说明:
1.一个include命令只能指定一个被包含文件。
2.如果文件1包含文件2,而文件2中要用到文件3的内容,则可在文件1中用两个include命令分别包含文件2和文件3,而且文件3应出现在文件2之前。如:#include”file3.h”#include”file2.h”。
形式2:#ifndef标识符
程序段1
#else
程序段2
#endif
它的作用是当所指定的标识符未被#define命令定义过,则在程序编译阶段只编译程序段1,否则编译程序段2。
形式3:#if表达式
程序段1
#else
程序段2
第九章预处理命令
第九章预处理命令第九章预处理命令编译预处理:在源程序文件中,加入“编译预处理命令”,使编译程序在对源程序进行通常的编译(包括词法分析、语法分析、代码生成、代码优化)之前,先对这些命令进行预处理,然后将预处理的结果和源程序一起再进行通常的编译处理,以得到目标代码(OBJ文件)。
C提供的编译预处理命令宏命令(Macro)文件包含命令(include)条件编译命令这些命令均以#开头,以区别于语句。
9.1 宏(Macro)定义一、不带参数的宏一般形式: #define 标识符字符串如: #define PI 3.1415926作用:用标识符(称为“宏名”)PI代替字符串“3.1415926”。
在预编译时,将源程序中出现的宏名PI替换为字符串“3.1415926”,这一替换过程称为“宏展开”。
#define:宏定义命令#undef:终止宏定义命令[例]#define PI 3.1415926main(){float l,s,r,v;printf("input radius:");scanf("%f",&r); /* 输入圆的半径 */l = 2.0*PI*r; /* 圆周长 */s = PI*r*r; /* 圆面积 */v = 4.0/3.0*PI*r*r*r; /* 球体积 */printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n",l,s,v);}说明:1、一般宏名用大写字母表示。
(变量名一般用小写字母)。
2、使用宏可以提高程序的可读性和可移植性。
如上述程序中,多处需要使用π值,用宏名既便于修改又意义明确。
3、宏定义是用宏名代替字符串,宏扩展时仅作简单替换,不检查语法。
语法检查在编译时进行。
4、宏定义不是C语句,后面不能有分号。
如果加入分号,则连分号一起替换。
如:#define PI 3.1415926;area = P*r*r;在宏扩展后成为:area = 3.1315926;*r*r;结果,在编译时出现语法错误。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
file2.c
包含文件的查找方法:
#include “文件名 ” 先在当前工作目录中去查找,若找不到再到指定
的标准目录中去查找。
#include <文件名>
直接到系统指定的标准目录中去查找。
如:对Turbo C编译系统,先在用户目录下查 找,然后在TC\include文件夹中查找。 如:对VC 6.0编译系统,直接在C:\Program Files\Microsoft Visual Studio\VC98\Include 文件夹中查找。
void main() { int a,b,c,d; char string[]="CHINA"; a=1;b=2;c=3;d=4; PR(D1,a); PR(D2,a,b); PR(D3,a,b,c); PR(D4,a,b,c,d); PR(S,string); } 运行结果: 1 12 123 1234 CHINA
宏展开:预编译时,用宏体替换宏名---不作语法检查
注意:
引号中的内容与宏名相同也不置换
例 #define PI 3.14159 printf(“2*PI=%f\n”,PI*2); 宏展开:printf(“2*PI=%f\n”,3.14159*2);
宏定义中使用必要的括号() 例 #define WIDTH 80 #define LENGTH (WIDTH+40) var=LENGTH*2; 宏展开:var= (80+40) *2;
例1: #ifdef TURBO #define int int #else #define int short #endif
可用于实现程序 在不同环境下的 兼容性。
例2:
#ifdef DEBUG 可用于进行程序 的调试。
printf(“x=%d,y=%d\n”,x,y); #endif 调试过程中,在程序前面加#define DEBUG 调试完成后,将前面的#define DEBUG删除掉
例9.1 使用不带参数的宏定义 #include <stdio.h> 运行: input radius: 4 #define PI 3.1415926 l=25.1328 void main() s=50.2655 { float l,s,r,v; v=150.7966 printf("input radius : "); scanf("%f",&r); l=2.0*PI*r; s=PI*r*r; v=4.0/3.0*PI*r*r*r; printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n",l,s,v); }
9.2 “文件包含”处理 <> 直接按标准目录搜索 功能:一个源文件可将另一个源文件的内容全部包含 “ ” 先在当前目录搜索,再搜索标准目录 进来 可指定路径 一般形式: #include “文件名” 或 #include <文件名> 处理过程:预编译时,用被包含文件的内容取代该预处 理命令,再将“包含”后的文件作为一个源文件单位 进行编译,得目标文件.obj
形式二:
# ifdef 标识符 程序段1 #endif
作用:当所指定的标识 符已经被#define 命令定 义过,则在程序编译阶 段只编译程序段1,
形式三:
# ifndef 标识符 程序段1 # else 程序段2 #endif 作用:当所指定的标识 符未被#define 命令定义 过,则在程序编译阶段 只编译程序段1,否则编 译程序段2。
本 章 小 结
(1) C语言的宏定义可以分为两种形式:一种是带参 数的宏定义;另一种是不带参数的宏定义。 (2)所谓文件包含预处理,是指在一个文件中将另外 一个文件的全部内容包含进来的处理过程,即将 另外的文件包含到本文件中。 (3)一般情况下,源程序中所有的行都参加编译。但 是有时希望对其中一部分内容只有在满足一定条 件下才进行编译,也就是对一部分内容指定编译 的条件,这就是“条件编译”。
例:输入一个口令,根据需要设置条件编译,使之在调试程序 时,按原码输出;在使用时输出“*”号。 #define DEBUG void main() { char pass[80];int i=1; printf("\nplease input password:"); do{i++; pass[i]=getchar(); #ifdef DEBUG putchar(pass[i]); #else putchar('*'); #endif } while(pass[i]!='\r'); …… }
定义的一般形式为: #if 表达式1 程序段1 #elif表达式2 程序段2 #elif表达式3 程序段3 ……
#else 程序段n #endif 这里的#elif的含义是“else if”。
程序举例:用同一程序实现大小写字母转换( 若定义UP转换为大写)
#include
"stdio.h" #define UP main() { char s[128]; gets(s); #ifdef UP strupr(s); #else strlwr(s); #endif puts(s); }
C语言程序设计
杨秋格 灾害信息工程系
第九章
预处理命令
主要内容
一、宏定义 #define #include 二、“文件包含”处理
三、条件编译 #if #else #endif
9.1 宏定义
宏定义命令
(1)不带参数的宏定义 一般形式: #define 标识符
宏体可缺省,表示宏名 定义过或取消宏体
字符串
例9.5 用宏代表输出格式 #include <stdio.h> #define PR printf #define NL "\n" #define D "%d" #define D1 D NL #define D2 D D NL #define D3 D D D NL #define D4 D D D D NL #define S "%s"
注意: 宏替换后,程序的原意表达。
#define PF(x) x*x /*#define PF(x) (x)*(x) */ /*#define PF(x) ((x)*(x)) */ main() 注意替换时不求值, { 只是字符串的原样替换 int a=2, b=3, c; c=PF(a+b)/PF(a+1); printf("\nc=%d ",c); } 按第一种宏定义:c=a+b*a+b/a+1*a+1;
按第二种宏定义:c=(a+b)*(a+b)/(a+1)*(a+1);
按第三种宏定义:c=((a+b)*(a+b))/((a+1)*(a+1));
带参数的宏替换与函数的主要区别
⑴函数调用时,先求出实参表达式的值,然后代入形参。而使 用带参的宏只是进行简单的字符替换。 ⑵函数调用是在程序运行时处理的,分配临时的内存单元。而 宏替换则是在编译时进行的,在展开时并不分配内存单元, 不进行值的传递处理,也没有“返回值”的概念。 ⑶宏替换不占运行时间,只占编译时间,而函数调用则占运行 时间。 ⑷函数中函数名及参数均有一定的数据类型,而宏不存在类型 问题,宏名及其参数无类型。
例9.4 使用宏带回几个结果 #include <stdio.h> #define PI 3.1415926 #define CIRCLE(R,L,S,V) L=2*PI*R;S=PI*R*R; V=4.0/3.0*PI*R*R*R void main() { float r,l,s,v; scanf("%f",&r); CIRCLE(r,l,s,v); printf("r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2f\n",r,l,s,v); } 宏展开后: 运行: void main() 3.5 { float r,l,s,v; r=3.50,l=21.99,s=38.48,v=179.59 scanf("%f",&r); l=2*3.1415926*r;s=3.1415926*r*r;v=4.0/3.0*3.1415926*r*r*r; printf("r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2f\n",r,l,s,v);}
二、使用常量表达式的值作为编译条件
形式: #if 表达式 程序段1 #else 程序段2 #endif
作用:当所指定的表达 式为真(非零)时就编 译程序段1,否则编译程 序段2。
可以事先给定一定条件,使程序在不 同的条件下执行不同的功能。
注意:#if和#endif必须配对使用。
带有#elif的条件编译
运行结果: 1 12 123 1234 CHINA
⑵ 主文件file1.c #include <stdio.h> #include "format.h" void main() { int a,b,c,d; char string[]="CHINA"; a=1;b=2;c=3;d=4; PR(D1,a); PR(D2,a,b); PR(D3,a,b,c); PR(D4,a,b,c,d); PR(S,string); }
例9.6 将例9.5改为文件包含 ⑴ 格式宏做成头文件format.h #define PR printf #define NL "\n" #define D "%d" #define D1 D NL #define D2 D D NL #define D3 D D D NL #define D4 D D D D NL #define S "%s"