C语言程序设计教案 第九章 编译预处理
c语言第09章编译预处理

9.1.2 符号常量
在定义无参宏时,如果“语言符号字符串”是一个 常量,则相应的“宏名”就是一个符号常量。 恰当命名的符号常量,除具有宏定义的上述优点外, 还能表达出它所代表常量的实际含义,从而增强程序的 可读性。 #define EOF -1 /*文件尾*/ #define NULL 0 /*空指针*/ #define MIN 1 /*极小值*/ #define MAX 31 /*极大值*/ #define STEP 2 /*步长*/
3.文件包含的优点 一个大程序,通常分为多个模块,并由多个程序员
分别编程。有和数据结构)或函数,集中到 一个单独的文件中。这样,凡是要使用其中数据或调用
其中函数的程序员,只要使用文件包含处理功能,将所
需文件包含进来即可,不必再重复定义它们,从而减少 重复劳动。
【例9.2】 #define MAX(a,b) (a>b)?a:b main(){ int x,y,max; printf("input two numbers: "); scanf("%d%d",&x,&y); max=MAX(x,y); printf("max=%d\n",max); } 上例程序的第一行进行带参宏定义,用宏名MAX表示条件表 达式(a>b)?a:b,形参a,b均出现在条件表达式中。程序第七行 max=MAX(x,y)为宏调用,实参x,y,将代换形参a,b。宏展开后 该语句为: max=(x>y)?x:y; 用于计算x,y中的大数。
【例9.3】 #define SQ(y) (y)*(y) main(){ int a,sq; printf("input a number: "); scanf("%d",&a); sq=SQ(a+1); printf("sq=%d\n",sq); }
C语言 第九章 预处理命令

目的: 简化程序的编写 ; 提高程序的模块化、可读性、可移植性。
有三种类型的预处理命令: 1. 宏定义命令; 2. 文件包含命令; 3. 条件编译命令。
为了与C语句区别,这些命令均以“ # ”开头。
处理流程: 第一次编译扫描时,将预编译命令处理完, 然后再进行正式编译,生成目标代码。
#define f(a)
(a)* b
若有:f(x+y) 则应有:
(x+y)b
若有:f(x+y+z) 则应有:
预编译后, z = f(x+y) 变成: z = x+y*b 结果为: z=31
(x+y+z)b
(这个结果与初始设想不一致)
“带参数宏定义” 必须注意以下几个方面: 1. 宏定义时要考虑实参(替换)的各种可能, 防止出 现二义性。
3. #include后的文件名既可用“ ”,也可用< >, 二者区别:
“ ”首先在当前目录中找,然后再去标准目录中找。
< > 只在标准目录(include目录)中找。
为提高预处理的搜索效率,通常对自定义的 非标准头文件使用方式一;而对系统提供的标准 头文件(如:math.h、stdio.h等)使用方式二。
将返回值 6 将返回值 8
但二者还是有区别的:
1) 宏替换在预编译时进行;
而函数调用在程序运行时进行
2) 宏展开时,仅仅是将宏体中的形参简单 地置换为实参,不计算实参值,也不会带来任何 返回值; 而函数调用要进行: l 计算实参值(假定用 2+3、 9–1作为实参将 被计算出来)、 l参数传递(将 5、8 传给形参x、y)、
这些文件要用到公用信息时,只要在文件 中加入#include “f.h”这么一行命令既可。这样 就不必在f1.c、…… 、fn.c每个文件中都去重 复定义这些公用的信息。
c语言第9章编译预处理

第9章编译预处理本章要求:1、熟悉宏定义与宏扩展。
a宏与函数的区别。
2、熟悉文件包含命令#include的作用及其预处理方法。
3、熟悉条件编译的使用。
概述编译预处理:在源程序文件中,加入“编译预处理命令”,使编译程序在对源程序进行通常的编译(包括词法分析、语法分析、代码生成、代码优化)之前,先对这些命令进行预处理,然后将预处理的结果和源程序一起再进行通常的编译处理,以得到目标代码(OBJ文件)。
C提供的编译预处理命令:宏命令(Macro)、文件包含命令(include)、条件编译命令这些命令均以#开头,以区别于语句。
9.1 宏定义(Macro)一、不带参数的宏一般形式: #define 标识符字符串如: #define PI 3.1415926作用:用标识符(称为“宏名”)PI代替字符串“3.1415926”。
在预编译时,将源程序中出现的宏名PI替换为字符串“3.1415926”,这一替换过程称为“宏展开”。
#define:宏定义命令#undef:终止宏定义命令[例9.1]#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、宏定义是用宏名代替字符串,宏扩展时仅作简单替换,不检查语法。
语法检查在编译时进行。
C语言程序设计课件:编译预处理

编译预处理
9.1 宏定义 9.2 文件包含 单元小结
编译预处理
9.1 宏 定 义
9.1.1 不带参数的宏定义 不带参数的宏定义的一般形式如下: # define 标识符 字符串 其作用是用一个指定的标识符来代表一个字符串。
说明:其中的“#”表示这是一条预处理命令;“define” 为宏定义命令;“标识符”为所定义的宏名;“字符串”可 以是常数、表达式、字符串等。例如:
926*r*r*r;
printf("r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2f\n",r,l,s,v);
}
编译预处理 图9-4 例9-4程序运行结果
编译预处理 实参r的值已知,可以从宏返回三个值:l、s、v。其实,
这只不过是字符置换而己,即将字符r置换R,l置换L,s置 换S,v置换V,而并未在宏展开时求出l、s、v的值。
# define MAX(x,y) (x)>(y)?(x):(y)
main()
{
int a,b,c,d,t;
…
t=MAX(a+b,c+d);
…
}
编译预处理 赋值语句展开后如下:
t=(a+b)>(c+d)?(a+b):(c+d);
MAX不是函数,程序中只有一个main函数,在main函 数中就能求出t的值。这个问题也可用函数的形式表示:
# define PI 3.14159 上述命令的作用是用标识符PI代替常量3.14159。在编 译预处理时,将程序中该定义以后的所有标识符PI都用 3.14159代替。
编译预处理
【例9-1】 输入圆的半径,求圆的周长、面积和球的体
《C语言程序设计》教案

(2)格式控制字符、格式控制项与printf类似,表3-3,4。一般使用更加简单形式.
注意: 数据读入结束情况:遇空格、TAB、回车;遇非法输入;指定宽度结束。
四、其它输入/输出函数
1、putchar函数 一般形式:putchar(字符表达式);
注意:C语言算术表达式的书写形式-数学表达式的书写形式区别:(1)-(4).
3、(算术)运算符的优先级与结合性(P.233附录IV)
先按运算符的“优先级别”高低次序执行;优先级别相同,则按规定的“结合方向”处理。为了清晰起见可用圆括号“()”强制.
例1:表达式a-b*c等价于a-(b*c)。 例2:a-b+c,到底是(a-b)+c还是a—(b+c)?(b先与a运算还是先与c参与运算?) 例3:分析x=y=z=3+5
3、实型数据的舍入误差。例2-3A。
四、字符型数据
1、字符常量表示.直接表示/转义表示(特殊的转义字符,一般字符也可以转义表示).
特殊转义字符对显示/打印的控制作用
2、字符变量-1个字节,char关键词。
3、字符数据的存储-ASCII码/二进制存储-C语言可以将字符看做很短的整数处理。
例2—7A,例2—8A可以看出字符数据的具有整数特性。
(2)格式控制字符d、o、x/X、u、c、s、f、e/E、g/G构成控制项的各种常见形式。表3-1,3—2。
注意:不要死记硬背,要总结规律.一般形式:%±m n h/l格式字符
2、scanf函数(格式输入函数)
(1)格式:scanf(格式控制字符串,输入表列-地址列表)
格式控制字符串:含义与printf类似
重点
C语言程序设计教案 第九章 编译预处理

第九章编译预处理课题:第九章编译预处理教学目的:1、了解预处理的概念及特点2、掌握有参宏与无参宏的定义及使用,领会文件包含的使用及效果教学重点:教学难点:掌握宏的使用,文件包含有参宏与无参宏的使用步骤一复习引导ANSI C标准规定可以在C源程序中加入一些“预处理命令”,以改进程序设计环境,提高编程效率。
这些预处理命令是由ANSI C统一规定的,但它不是C语言本身的组成部分,不能直接对它们进行编译。
必须在对程序进行通常的编译之前,先对程序中这些特殊的命令进行“预处理”,即根据预处理命令对程序作相应的处理。
经过预处理后程序不再包括预处理命令了,最后再由编译程序对预处理后的源程序进行通常的编译处理,得到可供执行的目标代码。
步骤二讲授新课C语言与其他高级语言的一个重要区别是可以使用预处理命令和具有预处理的功能。
C 提供的预处理功能主要有以下三种:宏定义、文件包含、条件编译。
分别用宏定义命令、文件包含命令、条件编译命令来实现。
为了与一般C语句相区别,这些命令以符号“ #” 开头。
§9.1宏定义宏:代表一个字符串的标识符。
宏名:被定义为“宏”的标识符。
宏代换(展开):在编译预处理时,对程序中所有出现的“宏名”,用宏定义中的字符串去代换的过程。
一、不带参数的宏定义一般形式:#define 标识符字符串#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 = 3.0/4*PI*r*r*r;printf(“%10.4f,%10.4f,%10.4\n”, l, s, v);}例如:由键盘输入y值,求表达式:3(y2+3y)+ 4(y2+3y)+ y(y2+3y)#define M (y*y+3*y)main(){ int s, y;printf( “Input a number :”); scanf (“%d”,&y);s=3*M+4*M+y*M; p rintf(“s=%d\n”,s);}先宏展开:s=3*(y*y+3*y) +4*( y*y+3*y) + y*(y*y+3*y)再与源程序合并说明:⑴宏名一般用大写表示,以便与变量名区分。
c语言第9章 编译预处理

源文件 pro.c
预处理程序 编译程序
头文件 stdio.h
预处理过程 目标文件 pro.obj
连接程序 目标文件 misc.obj 可执行程序 pro.exe 库 slibce.lib
5
第一节 编译预处理概述
预处理命令
预处理命令共有十二条, 预处理命令共有十二条,分为五类 : – 宏定义 – 文件包含 – 条件编译 – 行号和文件名控制 – 其它 宏定义, 这里介绍宏定义,文件包含和条件编译.为 了与一般C语句相区别 这些命令以符号" 开 语句相区别,这些命令以符号 了与一般 语句相区别 这些命令以符号"#"开 头. 6
第二节 宏定义
宏取消的一般形式为: 宏取消的一般形式为: #undef 宏替换名
取消宏定义
#undef用来删除事先定义了的宏定义.例如: 用来删除事先定义了的宏定义.例如 用来删除事先定义了的宏定义 #define LEN 100 #define WIDTH 200 char array[LEN][WIDTH]; #undef LEN #undef WIDTH
13
第二节 宏定义
例3:
带参数的宏定义
#define PI 3.1415926 #define S(r) PI*r*r 运行情况如下: 运行情况如下: main() r=3.600000 {float a,area; area=40.715038 a=3.6; area=S(a); printf("r=%f\narea=%f\n",a,area); }
18
带参数的宏定义
第二节 宏定义
带参数的宏定义
善于利用宏定义,可以实现程序的简化.如事先将 善于利用宏定义,可以实现程序的简化.
C语言程序设计-谭浩强-第9章预处理命令

17/14
§9.1 宏定义 宏体可缺省,表示宏名
不带参数宏定义
定义过或取消宏体
一般形式: 宏体] 一般形式: #define 宏名 [宏体 宏体 功能:用指定标识符 宏名)代替字符序列 宏体) 用指定标识符(宏名 代替字符序列(宏体 功能 用指定标识符 宏名 代替字符序列 宏体
如 #define 定义位置:任意YES 1 一般在函数外面) 定义位置 任意(一般在函数外面 任意 一般在函数外面 #define 例 NO 0 YES #define 1 作用域:从定义命令到文件结束 作用域 从定义命令到文件结束 main() #define PI 3.1415926 #define OUT printf(“Hello,World”); { …….. YES原作用域 #undef可终止宏名作用域 可 } 格式: 格式: #undef 宏名 #undef YES 宏展开:预编译时,用宏体替换宏名 用宏体替换宏名---不作语法检查 宏展开:预编译时 用宏体替换宏名 不作语法检查 #define YES 0 max() 引号中的内容与宏名相同也不置换 YES新作用域 {…….. if(x==YES)WIDTH 80 如 例 #define WIDTH 80 printf(“correct!\n”); 例 #define 宏定义可嵌套, 宏定义可嵌套,不能递归 } else if (x==NO)( WIDTH+40 ) printf(“error!\n”); #define #define LENGTH 3.14159 例 #define PI LENGTH WIDTH+40 宏定义中使用必要的括号() 宏定义中使用必要的括号() 展开后: if(x==1) 展开后var=LENGTH*2; : var=LENGTH*2;printf(“correct!\n”); (×) printf(“2*PI=%f\n”,PI*2); 例 #define MAX MAX+10 × else 宏展开: 宏展开: :printf(“2*PI=%f\n”,3.14159*2); 宏展开 宏展开:var= ((x==0) ) * 2;printf(“error!\n”); 宏展开: if 80+40 宏展开 :var= 80+40*2;
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第九章编译预处理课题:第九章编译预处理教学目的:1、了解预处理的概念及特点2、掌握有参宏与无参宏的定义及使用,领会文件包含的使用及效果教学重点:教学难点:掌握宏的使用,文件包含有参宏与无参宏的使用步骤一复习引导ANSI C标准规定可以在C源程序中加入一些“预处理命令”,以改进程序设计环境,提高编程效率。
这些预处理命令是由ANSI C统一规定的,但它不是C语言本身的组成部分,不能直接对它们进行编译。
必须在对程序进行通常的编译之前,先对程序中这些特殊的命令进行“预处理”,即根据预处理命令对程序作相应的处理。
经过预处理后程序不再包括预处理命令了,最后再由编译程序对预处理后的源程序进行通常的编译处理,得到可供执行的目标代码。
步骤二讲授新课C语言与其他高级语言的一个重要区别是可以使用预处理命令和具有预处理的功能。
C 提供的预处理功能主要有以下三种:宏定义、文件包含、条件编译。
分别用宏定义命令、文件包含命令、条件编译命令来实现。
为了与一般C语句相区别,这些命令以符号“ #” 开头。
§9.1宏定义宏:代表一个字符串的标识符。
宏名:被定义为“宏”的标识符。
宏代换(展开):在编译预处理时,对程序中所有出现的“宏名”,用宏定义中的字符串去代换的过程。
一、不带参数的宏定义一般形式:#define 标识符字符串#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 = 3.0/4*PI*r*r*r;printf(“%10.4f,%10.4f,%10.4\n”, l, s, v);}例如:由键盘输入y值,求表达式:3(y2+3y)+ 4(y2+3y)+ y(y2+3y)#define M (y*y+3*y)main(){ int s, y;printf( “Input a number :”); scanf (“%d”,&y);s=3*M+4*M+y*M; p rintf(“s=%d\n”,s);}先宏展开:s=3*(y*y+3*y) +4*( y*y+3*y) + y*(y*y+3*y)再与源程序合并说明:⑴宏名一般用大写表示,以便与变量名区分。
⑵使用宏名使程序易读,易修改。
⑶只作简单的置换,不作正确性检查。
⑷宏定义不是C语句,不必在行末加分号。
⑸宏名的作用域一般从自定义命令到本源文件结束。
⑹可以用# undef命令终止宏定义的作用域。
⑺宏定义允许嵌套,允许层层置换。
⑻宏名在源程序中用双引号括起来,则TC中预处理不对其作宏代换。
例:printf(“L=%f”, L); 中双引号内L不替换。
⑼宏定义与定义的变量不同,宏只作字符替换,不分配内存空间。
⑽对“输出格式”进行宏定义,可以减少书写麻烦例如:#define P printf#define D “%d,%d,%d\n”#define F “%6.2f,%6.2f,%6.2f\n”main(){ int a=5,c=8,e=11;float b=3.8,d=9.7; f=21.08;P(D,a,c,e);P(F,b,d,f);P(F,a+b,c+d,e+f);}二、带参数的宏定义格式:#define 宏名(参数表) 字符串例:#define s(a,b) a*b{……area =s(3,2);……}对带参的宏展开后,为area=3*2;例:#define M(y) y*y+3*y{……k=M(5);……}对其展开后,为k=5*5+3*5;说明:⑴对带参数的宏展开只是将宏名后括号内的实参字符串代替#define命令行中的形参。
⑵宏定义时,在宏名与带参数的括号之间不应加空格,否则将空格以后的字符都作为替代字符串的一部分。
⑶带参宏定义,形参不分配内存单元,因此不必作类型定义。
(与函数的区别之一)⑷带参宏与函数的区别之二:例如:main(){ int i=1;while( i<=5 ) printf(“%d\t”,SQ( i++));}SQ(int y){ return(y)*(y); }其结果为:1 4 9 16 25如:#define SQ(y) ((y)*(y))main(){ int i =1;while( i<=5 )printf(“%d\t”,SQ( i++));}运行结果:2 12 30例:利用宏定义求两个数中的大数。
#define MAX(a,b) (a>b)?a:bmain(){int x, y, max;scanf(“%d%d”, &x, &y);max =MAX(x, y);printf(“max=%d\n”, max);}带参的宏定义和函数不同:1、函数调用时,先求实参表达式值,后代入。
而带参的宏只是进行简单的字符替换。
2、函数调用是在程序运行时处理的,分配临时的内存单元。
而宏展开则是在编译时进行的,不分配内存单元,不进行值的传递,也无“返回值”。
3、对函数中的实参和形参都要定义类型,类型应一致。
而宏不存在类型问题,宏名和参数无类型,只是一个符号代表,展开时代入指定的字符即可。
4、调用函数只可得到一个返回值,而用宏可以设法得到几个结果。
5、使用宏次数多时,宏展开后使源程序增长,而函数调用不使源程序变长。
6、宏替换不占运行时间,只占编译时间。
而函数调用则占用运行时间( 分配单元、保留现场、值传递、返回)一般用宏代表简短的表达式比较合适。
也可利用宏定义实现程序的简化。
例9.5:#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”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.2 “文件包含”处理“文件包含”处理是指将指定的被包含文件的全部内容插到该控制行的位置处,使其成为源文件的一部分参与编译。
因此,被包含的文件应该是源文件。
通常置于源程序文件的首部,故也称为“头文件”。
C编译系统提供的头文件扩展名为“.h”,但设计者可根据实际情况,自行确定包含文件的后缀、名字及其位置。
一般形式,#include “文件名”或#include <文件名>文件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”文件file1.c#include “format.h”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、一个include命令只能指定一个被包含文件,如果要包含n个文件,要用n个include命令。
2、如果文件1包含文件2,而文件2中要用到文件3的内容,则可在文件1中用两个include 命令分别包含文件2和文件3,而且文件3应出现在文件2之前,即在“file1.c”中定义:#include “file3.h”#include “file2.h”3、在一个被包含文件中又可以包含另一个被包含文件,即文件包含是可以嵌套的。
4、被包含文件(file2.h)与其所在的文件(file1.c),在预编译后已成为同一个文件。
5、在#include 命令中,文件名可以用双引号或尖括号括起来。
如:#include <file2.h>或#include “file2.h”二者的区别:用尖括号时称为标准方式,系统到存放C库头文件所在的目录中寻找要包含的文件。
用双引号时,系统先在用户当前目录中寻找要包含的文件,若找不到,再按标准方式查找。
#include “c:\tc\include\myfile.h” /*正确*/#include <c:\test\file.c> /*正确*/#include <c:\tc\include\stdio.h> /*错误*/用尖括号:带路径:按指定路径去寻找被包含文件,但此时被包含文件不能以“.h”结尾,否则错误。
不带路径:仅从指定标准目录下找。
用引号:带路径:按指定路径去寻找被包含文件,不再从当前目录和指定目录下找。
不带路径:先在当前目录下找,找不到再在系统指定的标准目录下找。
步骤三课堂小结本课主要讲解了宏定义、“文件包含”处理。
对带参数的宏的使用,及与函数的使用的区别。
搞清经常使用的头文件。
步骤四布置作业上机作业:(第九章课后练习)9.4书面作业:(第九章课后练习)9.7、9.8。