第9聋 预处理命令
第9章预处理命令 本章内容 1.宏定义 2."文件包含"处理 3.条件编译
-2- 第9章 预处理命令 本 章 内 容 1. 宏定义 2. "文件包含"处理 3. 条件编译
第9章预处理命令 9.1宏定义 ■基本概念 ◆预处理命令 由 ANSI C统一规定,不是C语言本身的组成部分。 预处理的实现 宏定义 文件包含 条件编译
-3- 第9章 预处理命令 9.1 宏定义 基本概念 v 预处理命令 由ANSI C统一规定,不是C语言本身的组成部分。 v 预处理的实现 宏定义 文件包含 条件编译
第9章预处理命令 9.1宏定义 不带参数的宏定义 ◇一般形式:# efine标识符字符串 例如: define P 3.1415926 ☆说明 宏名一般用大写字母表示,以便与变量名相区别 ■宏定义是用宏名代替一个字符串,只作简单的置换,不作正 确性检査。 宏定义不是C语句,不必在行末加分号。 # define命令应放在程序中函数的外面,有效范围为定义命 令之后到本源文件结束。 可以用# undef命令终止宏定义的作用域。 在进行宏定义时,可以引用已定义的宏名,可以层层置换。 (例9.2) 对程序中用双引号括起来的字符串内的字符,即使与宏名相 同,也不进行置换。 ■宏定义与定义变量的含义不同,不分配内存空间
-4- 第9章 预处理命令 9.1 宏定义 不带参数的宏定义 v 一般形式: #define 标识符 字符串 例如: #define PI 3.1415926 v 说明 宏名一般用大写字母表示,以便与变量名相区别。 宏定义是用宏名代替一个字符串,只作简单的置换,不作正 确性检查。 宏定义不是C语句,不必在行末加分号。 #define命令应放在程序中函数的外面,有效范围为定义命 令之后到本源文件结束。 可以用#undef命令终止宏定义的作用域。 在进行宏定义时,可以引用已定义的宏名,可以层层置换。 (例9.2) 对程序中用双引号括起来的字符串内的字符,即使与宏名相 同,也不进行置换。 宏定义与定义变量的含义不同,不分配内存空间
第9章预处理命令 9.1宏定义 带参数的宏定义 ◆一般形式# define宏名(参数表)字符串 例如: #def ine s(a, b) a*b area =S(2, 3) 宏定义的展开:实参与虚参相对应,从左到右进行置换。 ◆例9.3: define P 3.1415926 #def ine s (r) Pl*r*r main o float a, area: a=3.6 area =S(a) printf(" %f, %f", a, area) 如果有语句:area=S(a+b);分析程序正误?
-5- 第9章 预处理命令 9.1 宏定义 带参数的宏定义 v 一般形式 #define 宏名(参数表) 字符串 例如: #define S(a, b) a*b area = S(2, 3); 宏定义的展开:实参与虚参相对应,从左到右进行置换。 v 例9.3: 如果有语句:area = S(a+b);分析程序正误? #define PI 3.1415926 #define S(r) PI*r*r main() { float a, area; a = 3.6; area = S(a); printf("%f, %f", a, area); }
第9章预处理命令 9.1宏定义 ◆说明 带参的宏定义,在定义时,在字符串中的形式参数外面加 个括号。 ■在宏定义时,在宏名与带参数的括号之间不应加空格,否则 将空格以后的字符都作为替代字符串的一部分。 ◇带参的宏定义与函数的不同 函数调用时,先求出实参表达式的值,然后代入形参。而使 用带参的宏只是进行简单的字符替换 函数调用在程序运行时处理,为形参分配临时的内存单元。 而宏展开是在编译时进行,不分配内存单元,不进行值的传 递处理,也没有"返回值"的概念 函数中的实参和形参都有相应的类型定义。而宏不存在类型 问题,宏名无类型,它的参数也无类型。 ■调用函数只可得到一个返回值,而用宏可以得到几个结果
-6- 第9章 预处理命令 9.1 宏定义 v 说明 带参的宏定义,在定义时,在字符串中的形式参数外面加一 个括号。 在宏定义时,在宏名与带参数的括号之间不应加空格,否则 将空格以后的字符都作为替代字符串的一部分。 v 带参的宏定义与函数的不同 函数调用时,先求出实参表达式的值,然后代入形参。而使 用带参的宏只是进行简单的字符替换。 函数调用在程序运行时处理,为形参分配临时的内存单元。 而宏展开是在编译时进行,不分配内存单元,不进行值的传 递处理,也没有"返回值"的概念。 函数中的实参和形参都有相应的类型定义。而宏不存在类型 问题,宏名无类型,它的参数也无类型。 调用函数只可得到一个返回值,而用宏可以得到几个结果
第9章预处理命令 9.1宏定义 例9.4 define Pl 3.1415926 #def ine CIRCLE(R, L, S)L=2*Pl*R: S=PI*R*R ma In float r. scanf("%f", &r) CIRCLE(r, D pr intf("‰6.2f,‰6.2f,%.2f",r,l,s); ■宏展开后源程序增长,而函数调用不使源程序变长。 宏替换不占运行时间,只占编译时间。而函数调用则占运行 时间。 ◇对一些简短的功能实现,用宏和函数都可以。 例9.5(略)
-7- 第9章 预处理命令 9.1 宏定义 例 9.4: 宏展开后源程序增长,而函数调用不使源程序变长。 宏替换不占运行时间,只占编译时间。而函数调用则占运行 时间。 v 对一些简短的功能实现,用宏和函数都可以。 例9.5(略) #define PI 3.1415926 #define CIRCLE(R, L, S) L=2*PI*R; S=PI*R*R main() { float r, l; scanf("%f", &r); CIRCLE(r, l); printf("%6.2f, %6.2f, %6.2f", r, l, s); }
第9章预处理命令 9.2文件包含处理 文件包含 今一个源文件可以将另一个源文件的全部内容包含进来,称为文件 包含 ◆命令形式 # include"文件名 或 # inc lude (标准方式) filel.c file2.c filel.c #include B A ◇编译时两个文件作为一个源程序进行编译,得到一个目标文件
-8- 第9章 预处理命令 9.2 文件包含处理 文件包含 v 一个源文件可以将另一个源文件的全部内容包含进来,称为文件 包含。 v 命令形式 #include "文件名" 或 #include (标准方式) file1.c file2.c file1.c v 编译时两个文件作为一个源程序进行编译,得到一个目标文件。 #include A B B A
第9章预处理命令 9.2文件包含处理 说明: ◆一个# include命令只能指定一个被包含文件 ◇如果文件1包含文件2,而文件2中要用到文件3的内容,则在文件 1中有: i inc ude file3. h i ude file2. h ◇文件包含可以嵌套。 filel.c file2.c file3.c #inc lude "file2. c"#inc l ude " file3.c ☆两种文件包含形式的区别(P196) 尖括号系统到存放C库函数头文件所在的目录中寻找要包含 的文件,称为标准方式。 双撇号系统先在用户当前目录中寻找要包含的文件,若找 不到,再按标准方式查找。若文件不在当前目录中,双撇号 内可给出文件路径
-9- 第9章 预处理命令 说明: v 一个#include命令只能指定一个被包含文件。 v 如果文件1包含文件2,而文件2中要用到文件3的内容,则在文件 1中有: #include "file3.h" #include "file2.h" v 文件包含可以嵌套。 file1.c file2.c file3.c v 两种文件包含形式的区别(P196) 尖括号 系统到存放C库函数头文件所在的目录中寻找要包含 的文件,称为标准方式。 双撇号 系统先在用户当前目录中寻找要包含的文件,若找 不到,再按标准方式查找。若文件不在当前目录中,双撇号 内可给出文件路径。 9.2 文件包含处理 #include "file2.c " … #include "file3.c " …
第9章预处理命令 9.3条件编译 条件编译 ☆指定编译的条件,仅对部分内容进行编译,称为条件编译。 条件编译命令的几种形式: 例如: (1) #fdef标识符 define DEBUG 程序段1 ifdef deBug # eI se pr intf( x=%d",x) 程序段2 # e se #end if pr intf(y=%d", y) dend if 说明: #else部分可以省略。 ◆程序段可以是语句组也可以是命令行。 10
-10- 第9章 预处理命令 9.3 条件编译 条件编译 v 指定编译的条件,仅对部分内容进行编译,称为条件编译。 条件编译命令的几种形式: (1) #ifdef 标识符 程序段1 #else 程序段2 #endif 说明: v #else 部分可以省略。 v 程序段可以是语句组也可以是命令行。 例如: #define DEBUG ... #ifdef DEBUG printf(" x=%d", x); #else printf(" y=%d", y); #endif