第8章编译预处理 本章学习目标 预处理命令的使用可以改进程序设计环 境,提高编程效率,使程序具有可移植性。 本章将详细讲解宏的定义和使用及条件编 译,通过本章的学习,读者应该掌握以下 内容: ■ 宏定义 ■ 条件编译
第8章 编译预处理 本章学习目标 预处理命令的使用可以改进程序设计环 境,提高编程效率,使程序具有可移植性。 本章将详细讲解宏的定义和使用及条件编 译,通过本章的学习,读者应该掌握以下 内容: ◼ 宏定义 ◼ 条件编译
8.1宏定义 8.11相关知识 宏定义的作用是用标识符来代表一串字符,相当于给 一串字符命名。 8.1.2程序范例 程序8-l:使用#undef终止宏定义。 #define PI 3.14159 #include mainO {
8.1 宏定义 8.1.1 相关知识 宏定义的作用是用标识符来代表一串字符,相当于给 一串字符命名。 8.1.2 程序范例 程序8-1:使用#undef终止宏定义。 #define PI 3.14159 #include main() {
printf("main:%f",PI); func(); } #undef PI /*终止宏定义*/ func() { printf("func:%of",PI); /*认识的符号名PI* return;
printf("main:%f",PI); func(); } #undef PI /﹡终止宏定义﹡/ func() { printf("func:%f",PI); /﹡认识的符号名PI﹡/ return; }
这个程序由于在func(函数前,通过#undef PI终止了宏名 PI的作用域,而func(函数又使用了宏名PI,因而是错误 的。去掉#undef PI程序就是正确的了。 8.1.3知识归纳 1.C语言的宏定义格式 (1)无参宏定义。 无参宏定义一般格式为: #define标识符一串字符 标识符被定义为代表一串字符的宏名。例如:
这个程序由于在func()函数前,通过#undef PI终止了宏名 PI的作用域,而func()函数又使用了宏名PI,因而是错误 的。去掉 #undef PI程序就是正确的了。 8.1.3 知识归纳 1.C语言的宏定义格式 (1)无参宏定义。 无参宏定义一般格式为: #define 标识符 一串字符 标识符被定义为代表一串字符的宏名。例如:
#define E 2.71828 这里的E就是宏名,它代表一串字符2.71828。该宏名在编译 预处理时被置换成宏定义中的2.71828,这个置换过程称为 宏展开。 宏定义命令应按以下规则正确使用: 1)#号与define,之间一般不留空格,但宏名左右两边必须至 少用一个空格分隔。 2)宏名习惯上采用大写字母表示,以与变量名相区别,但 也可用小写字母
#define E 2.71828 这里的E就是宏名,它代表一串字符2.71828。该宏名在编译 预处理时被置换成宏定义中的2.71828,这个置换过程称为 宏展开。 宏定义命令应按以下规则正确使用: 1)#号与define之间一般不留空格,但宏名左右两边必须至 少用一个空格分隔。 2)宏名习惯上采用大写字母表示,以与变量名相区别,但 也可用小写字母
3)宏定义中的一串字符不能以分号“;”结尾,否则分号 作为一串字符的一部分参加宏展开,会造成编译时出错。 4)宏名的有效范围为定义之初到本源文件结束,出了这个 文件,宏名便失去了作用。c语言允许#define命令出现在 程序中的任何位置,但一般情况下,#define.总是在程序 的开头,函数之前。 5)一个经#define定义的宏名,也可在程序中通过#undef终 止其作用域。请看例8-1。 6)在一个宏定义中,可以引用已定义的宏名,可以进行层 层转换
3)宏定义中的一串字符不能以分号“ ; ”结尾,否则分号 作为一串字符的一部分参加宏展开,会造成编译时出错。 4)宏名的有效范围为定义之初到本源文件结束,出了这个 文件,宏名便失去了作用。C语言允许#define命令出现在 程序中的任何位置,但一般情况下,#define总是在程序 的开头,函数之前。 5)一个经#define定义的宏名,也可在程序中通过#undef终 止其作用域。请看例8-1。 6)在一个宏定义中,可以引用已定义的宏名,可以进行层 层转换
7)若宏名出现被双引号括起的一串字符中时,将不会产生 宏替换。例如: #define PI 3.14159 printf("PI=%f\n",PI); 不替换替换 8)宏定义还可以定义运算符、表达式乃至一些有关的提示 信息。用宏名代替表达式的例子如下: #define CIRCLE 2.0 3.14159
7)若宏名出现被双引号括起的一串字符中时,将不会产生 宏替换。例如: #define PI 3.14159 . printf("PI=%f\n",PI); 不替换 替换 8)宏定义还可以定义运算符、表达式乃至一些有关的提示 信息。用宏名代替表达式的例子如下: #define CIRCLE 2.0﹡3.14159
(2)带参宏定义。 在程序设计中,宏定义除了定义符号常量外,还经常用于定 义带参的宏。带参宏定义的一般格式为: #define?宏名(参数表)字符串 例如: #define SUM(a,b)a+b 其中SUM是带参数的宏,a,b为形式参数,在此定义后,在 程序中可用$UM来代替两变量相加的运算,例如: y=SUM(3,5) 等价于y=3+5 z=SUM(3*2,5/2) 等价于z=3*2+5/2
(2)带参宏定义。 在程序设计中,宏定义除了定义符号常量外,还经常用于定 义带参的宏。带参宏定义的一般格式为: #define宏名(参数表)字符串 例如: #define SUM(a,b) a+b 其中SUM是带参数的宏,a,b为形式参数,在此定义后,在 程序中可用SUM来代替两变量相加的运算,例如: y=SUM(3,5) 等价于y=3+5 z=SUM(3*2,5/2) 等价于z=3*2+5/2
在编译预处理时,带参数的宏用它的定义式置换,其中的形 式参数用实参置换。 2.注意的问题 带参的宏的使用规则与无参宏类似,但是因为带参的宏含有 参数,因此在使用中要注意几个概念上的问题。 首先,使用带参的宏一定要注意定义中圆括号的用法。 其次,带参数的宏在程序中使用时,它的使用形式和特性与 函数相似,但它们本质上是完全不同的,其区别在于: (1)在程序控制上,函数的调用需要进行控制的转换,而 使用带参数的宏则仅是表达式的运算
在编译预处理时,带参数的宏用它的定义式置换,其中的形 式参数用实参置换。 2.注意的问题 带参的宏的使用规则与无参宏类似,但是因为带参的宏含有 参数,因此在使用中要注意几个概念上的问题。 首先,使用带参的宏一定要注意定义中圆括号的用法。 其次,带参数的宏在程序中使用时,它的使用形式和特性与 函数相似,但它们本质上是完全不同的,其区别在于: (1)在程序控制上,函数的调用需要进行控制的转换,而 使用带参数的宏则仅是表达式的运算
(2) 带参数的宏一般是运算表达式,所以不像函数那样有 一定的数据类型。宏的数据类型可以说是表达式运算结果 的类型,随着使用的实参不同,运算结果呈现的数据类型 也不同。例如: #define MAX(x,y)(x>y)?(x):(y) 程序中出现: a=MAX(3,5) /*则结果为整型*/ b=MAX3.5,4.2) /*则结果是实型*/ (3)在调用函数时,对使用的实参有数据类型限制,要求 与形参一致。而带参数的宏的实参可以是任意数据类型
(2)带参数的宏一般是运算表达式,所以不像函数那样有 一定的数据类型。宏的数据类型可以说是表达式运算结果 的类型,随着使用的实参不同,运算结果呈现的数据类型 也不同。例如: #define MAX(x,y) (x>y)?(x):(y) 程序中出现: a= MAX(3,5) /﹡则结果为整型﹡/ b= MAX(3.5,4.2) /﹡则结果是实型﹡/ (3)在调用函数时,对使用的实参有数据类型限制,要求 与形参一致。而带参数的宏的实参可以是任意数据类型