2022年编译预处理[归 .pdf
8 编译预处理 本章重点: 宏定义命令 条件编译命令 文件包含命令 本章难点: 带参宏定义 条件编译 在 C语言源程序中,除了为实现程序功能而使用的声明语句和执行语句之外,还可以使用编译预处理命令。所谓编译预处理是指,在对源程序进行编译之前,先对源程序中的编译预处理命令进行处理;然后再将处理的结果和源程序一起进行编译,得到目标代码。 C 语言提供的编译预处理命令主要有宏定义、条件编译和文件包含等三种。为了能够和一般 C语句区别开来,编译预处理命令以“#”号开头。它占用一个单独的书写行,命令行末尾没有分号。编译预处理是语言的一个重要功能,合理地使用编译预处理功能编写的程序便于阅读、修改、调试和移植,也有利于模块化程序设计。 8.1 宏定义 宏定义是指将一个标识符( 又称宏名 ) 定义为一个字符串 ( 或称替换文本 ) 。在编译预处理时,对程序中出现的所有宏名都用相应的替换文本去替换,这称为“宏替换”或“宏展开” 。 在语言中,“宏定义”可分为无参宏定义和带参宏定义两种。8.1.1 无参宏定义 无参宏定义即定义没有参数的“宏”,其一般形式为: #define 标识符 替换文本 其中#define表示该语句行是宏定义命令,“标识符”为所定义的宏名,习惯上宏名用大写字母表示;“替换文本” 可以是常量、 关键字、 表达式、 语句等任意字符串。在 define 、宏名和替换文本之间分别用空格隔开。 #define命令可以不包含“替换文本”,此时仅说明宏名已被定义,以后可以使用。 第 2 章介绍的符号常量的定义就是一种无参宏定义。 例 8-1 用无参宏定义计算s=3*(y*y+3*y)+4*(y*y+3*y)+5*(y*y+3*y)。 算法分析:在计算式子中出现了三个(y*y+3*y) ,为减少书写量,可使用宏定义。程序如下:名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 14 页 - - - - - - - - - #define M (y*y+3*y) main() int s,y; printf(Please input a number: ); scanf(%d ,&y); s=3*M+4*M+5*M; printf(s=%dn,s); 运行情况如下: Please input a number: 4 s=336 在上面程序的语句s=3*M+4*M+5*M; 中引用了3 次宏 M ,经“宏展开”后该语句变为: s=3*(y*y+3*y)+4*(y*y+3*y)+5*(y*y+3*y); 符合题目要求。注意在宏定义中替换文本(y*y+3*y) 两边的括号不能少,否则会产生错误。如改为以下定义: #difine M y*y+3*y 则在宏展开时将得到下述语句: s=3*y*y+3*y+4*y*y+3*y+5*y*y+3*y; 显然与原题意要求不符,计算结果当然是错误的。因此在进行宏定义时必须注意,应保证在宏代换之后不发生错误。 对于无参宏定义还要说明以下几点: (1) 习惯上宏名用大写字母表示,以便与变量名区别开。但这并非规定,也允许使用小写字母。 (2) 用替换文本替换宏名只是一种简单的直接替换,替换文本中可以包含任意字符,系统在进行编译预处理时对它不作任何检查。例如: #define PI 3.l415926 即不小心将替换文本中的第一个数字“1”错写成了小写字母“ l ”,不再表示圆周率的近似值,预处理时仍然把PI 替换成 3.l415926 ,而不管含义如何。在编译时才发现错误并报错。 (3) 宏定义不是声明或执行语句,在行末不要加分号,如果加上分号则连分号也一起替换。 (4) 一个#define只能定义个宏,且一行只能定义一个宏。若需要定义多个宏就要使用多个 #define ,并写在多行上。 (5) 宏定义时如果一行写不下,可用“ ”续行。 例如: #define PI 3.1415926 /*正确*/ #define PI 3.1415 926 /*正确*/ (6) 宏定义原则上可以出现在源程序的任何地方,但通常写在函数之外,其作用域为名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 14 页 - - - - - - - - - 从宏定义命令起到源程序文件结束。如要终止其作用域可使用#undef命令,其用法为: #undef 标识符如:#undef PI (7) 宏名在源程序中若用双撇号括起来,则在编译预处理时不对其作宏替换。也就是说,宏名被双撇号括起来时,仅作为一般字符串使用。 例 8-2 宏替换的选择性。 #define PI 3.1415926 main() printf(PI is %9.7f.n,PI); 程序运行结果为: PI is 3.1415926. 例 8-2 中定义宏名PI 表示 3.1415926,但在 printf函数中第一个PI 被双撇号括起来,因此不进行宏替换, 只把该“ PI”当普通的字符串处理,而第二个 PI 没有被双撇号括起来,因此被替换成了3.1415926。 (8) 宏定义允许嵌套,在宏定义的替换文本中可以使用已经定义过的宏名。在宏展开时层层替换。 例如: #define PI 3.1415926 #define S PI*r*r /* PI是已定义的宏名 */ 对语句: printf(%f,S); 在宏替换后变为: printf(%f,3.1415926*r*r); 使用无参宏定义还可以实现程序的个性化( 如用自己所习惯的符号表示数据类型或输出格式等 ) ,使程序的书写、阅读更加方便。 例 8-3 用无参宏定义表示常用的数据类型和输出格式。#define INTEGER int #define REAL float #define P printf #define D %dn#define F %fnmain() INTEGER a=5, c=8, e=11; REAL b=3.8, d=9.7, f=21.08; P(D F,a,b); P(D F,c,d); P(D F,e,f); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 14 页 - - - - - - - - - 程序运行结果为: 5 3.800000 8 9.700000 11 21.080000 8.1.2 带参宏定义 语言允许“宏”带有参数。在宏定义中的参数称为形式参数,在引用带参宏时给出的参数称为实际参数。 带参宏定义的一般形式为: #define 宏名( 形参表 ) 替换文本其中,形参表由一个或多个形参组成,各形参之间用逗号隔开,替换文本中通常应包括有形参。 引用带参宏的一般形式为: 宏名( 实参表)带参宏定义展开时先把宏引用替换为替换文本,再将替换文本中出现的形参用实参代替。例如下面的宏定义和引用: #define M(y) y*y+3*y /*宏定义 */ k=M(5); /*宏引用 */ 宏展开时,先用y*y+3*y 替换 M(5),再将替换文本中的形参y 用实参 5 代替,最终得到: k=5*5+3*5; 例 8-4 用带参宏定义求两数中的大者。#define MAX(a,b) (ab)?a:b main() int x,y,max; printf(input two numbers(x,y): ); scanf(%d,%d ,&x,&y); max=MAX(x,y); printf(max=%dn ,max); 程序运行情况如下: input two numbers(x,y): 5,6 max=6 这里的宏MAX(a,b)既可以比较int型数据,也可以比较float型、char 型等各种类型数据。若要比较float型数据,只需将程序第3 行改为: 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 14 页 - - - - - - - - - float x,y,max; 并在输入输出格式控制处将“%d ”改为“ %f”即可,宏定义无需改动。 如果用函数实现上述功能,则需要写相应的两个函数才可以。 对于带参宏定义,除了需要遵守一些与无参宏定义一样的规则,如一个#define命令只能定义一个带参宏,通常在函数外定义,允许嵌套、续行、使用#undef命令终止宏定义等,另外还应注意以下几点: (1) 在带参宏定义中,宏名与其后的左括弧“( ”之间不得有空格,否则将变为无参宏定义。 例如把: #define MAX(a,b) (ab)?a:b 写为: #define MAX (a,b) (ab)?a:b 将被认为是无参宏定义,宏名是MAX ,替换文本为 (a,b) (ab)?a:b。对下面的语句:max=MAX(x,y); 进行宏替换后,将变为: max=(a,b) (ab)?a:b(x,y); 这显然是错误的。 (2) 在带参宏定义中,替换文本中的形参通常要用括号括起来以避免出错。 例 8-5 分别引用以下宏定义,求3*F(3+2) 的值。 (A) #define F(x) x*x+x (B) #define F(x) (x)*(x)+(x) (C) #define F(x) (x*x+x) (D) #define F(x) (x)*(x)+(x) 解:表达式 3*F(3+2) 在分别引用以上4 个宏定义后,其值为: (A) 22 。因为宏定义只作为一种简单的字符替换,所以在引用(A) 中的宏定义后,表达式 3*F(3+2) 被替换为3*3+2*3+2+3+2。 (B) 80 。表达式3*F(3+2) 被替换为: 3*(3+2)*(3+2)+(3+2)。 (C) 48 。表达式3*F(3+2) 被替换为: 3*(3+2*3+2+3+2) 。 (D) 90 。表达式3*F(3+2) 被替换为: 3*(3+2)*(3+2)+(3+2)。 由此可见, 使用带参数的宏定义,替换文本中的括号位置不同,可以得出不同的结果。使用时一定要仔细考虑。 (3) 宏定义也可用来定义多个语句,在宏替换时,把这些语句都替换到源程序中。 例 8-6 一个宏定义代表多个语句。#define SSSV(s1,s2,s3,v) s1=l*w; s2=l*h; s3=w*h; v=w*l*h; main() int l=3,w=4,h=5,sa,sb,sc,vv; SSSV(sa,sb,sc,vv); printf(sa=%dnsb=%dnsc=%dnvv=%dn,sa,sb,sc,vv); 程序运行结果为: 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 14 页 - - - - - - - - - sa=12 sb=15 sc=20 vv=60 程序第一行为宏定义,用宏名 SSSV 表示 4 个赋值语句, 4个形参分别为4个赋值符左边的变量。在宏替换时,把4 个语句展开并用实参代替形参,得到计算结果。 应该注意的是,带参宏定义和函数有一定的相似之处。如表示形式都是由一个名字加上参数表组成,都要求实参与形参的数目相同等。因此,很多读者容易将它们混淆。下面将带参宏定义与函数的主要区别列出,以帮助读者更快地掌握带参宏定义。 带参宏定义与函数的主要区别如下: (1) 定义方式不同。带参宏使用预处理命令#define定义;而函数使用函数定义。 (2) 参数性质不同。带参宏的参数表中的参数不必说明其类型,也不分配存储空间;而函数参数表中的参数需说明其类型并为其分配存储空间。 (3) 实现方式不同。宏展开是在编译时由预处理程序完成的,不占用运行时间;而函数调用是在程序运行时进行,需占用一定的运行时间。 (4) 参数传递不同。若实参为表达式,引用带参宏时只进行简单的字符替换,不计算实参表达式的值;而函数调用时,则先计算表达式的值,然后代入形参。 (5) 返回值不同。带参宏定义无返回值;而函数有返回值。 例 8-7 带参宏定义的实参是表达式的情况。#define SQ(y) (y)*(y) main() int a,sq; printf(input a number: ); scanf(%d ,&a); sq=SQ(a+1); printf(sq=%dn,sq); 程序运行情况如下: input a number: 3 sq=16 程序中定义了带参宏SQ(y),在引用时实参为表达式a+1。在宏展开时,先用 (y)*(y) 替换 SQ(a+1),再用实参表达式a+1 替换形参y,最后得到如下语句: sq=(a+1)*(a+1); 这与函数的调用是不同的,函数调用时要先把实参表达式的值求出来,再赋予形参。而宏引用时对实参表达式不作计算,直接照原样替换。可简单总结为“完全展开,直接代替” 。 例 8-8 函数与带参宏定义的进一步比较。#define SQ_MACRO(y) (y)*(y) main() 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 14 页 - - - - - - - - - int i=1; printf(SQ_fun:n ); while(i=5) printf(%dn,SQ_fun(i+); i=1; printf(SQ_MACRO:n ); while(i=5) printf(%dn,SQ_MACRO(i+); SQ_fun(int y) return(y)*(y); 程序运行结果为: SQ_fun: 1 4 9 16 25 SQ_MACRO: 2 12 30 此题本意是用函数调用和宏引用来分别实现输出15 的平方值。 但程序中, 函数调用是把实参i 的值传给形参y 后自增 1,因而要循环5 次,输出 15的平方值。 而在宏引用时, SQ_m(i+)被替换为 (i+)*(i+)。在第一次循环时,i等于 1,其计算过程为:表达式中前一个i 为 1,然后 i 自增 1 变为 2,此时表达式中第2 个 i 为 2,二者相乘的结果为2,然后 i 值再自增 1 为 3。在第二次循环时,i已为 3,因此表达式中前一个 i 为 3,后一个 i 为 4,乘积为 12,然后 i 再自增 1 变为 5。进入第三次循环,由于i 值已为 5,所以这将是最后一次循环。计算表达式的值为5*6 等于 30,并且 i 值变为 7,不再满足循环条件,跳出循环,最后只输出三个值,事与愿违。 从以上分析可以看出函数调用和宏引用二者虽然在形式上非常相似,但在本质上是完全不同的。 8.2 条件编译 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 14 页 - - - - - - - - - 条件编译是在编译源文件之前,根据给定的条件决定编译的范围。一般情况下,源程序中所有语句都参加编译。但有时希望在满足一定条件时,编译其中的一部分语句,在不满足条件时编译另一部分语句。这就是所谓的 “条件编译” 。条件编译对于程序的移植和调试是很有用的。在一套程序要产生不同的版本( 如演示版本和实际版本 ) 、避免重复定义时往往使用条件编译。 条件编译有以下三种形式。 (1) 第一种形式: #ifdef 标识符 程序段 1 #else 程序段 2 #endif 它的功能是, 如果标识符是已被 #define命令定义过的宏名, 就对程序段1 进行编译;否则对程序段2 进行编译。 如果没有程序段2(为空) ,则本格式中的 #else可以省略, 即可以写为: #ifdef 标识符 程序段 #endif 例 8-9 根据需要设置条件编译,使之能控制对一些提示信息的输出。 #define DEBUG main() int a=4; #ifdef DEBUG printf(Now the programmer is debugging the program.); #else printf(a=%d.,a); #endif 程序运行结果为: Now the programmer is debugging the program. 若没有第一行的宏定义命令,程序运行后会输出: a=4. (2) 第二种形式: #ifndef 标识符 程序段 1 #else 程序段 2 #endif 与第一种形式的区别是将“ifdef ”改为“ ifndef ”。它的功能是,如果标识符未被名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 14 页 - - - - - - - - - #define命令定义过,则对程序段1 进行编译,否则对程序段2 进行编译。这与第一种形式的功能刚好相反。 (3) 第三种形式: #if 常量表达式 程序段 1 #else 程序段 2 #endif 它的功能是,如果常量表达式的值为真( 非0),则对程序段1 进行编译,否则对程序段 2 进行编译。因此可以使程序在不同条件下,完成不同的功能。 例 8-10 设置一个开关,判断输入值是半径还是边长,实现求圆或正方形的面积。#define R 1 main() float c,r,s; printf (input a number:); scanf(%f,&c); #if R r=3.14159*c*c; printf(area of round is: %fn,r); #else s=c*c; printf(area of square is: %fn,s); #endif 程序运行情况如下: input a number:3 area of round is: 28.274309 若程序的第一行改为: #define R 0 则程序运行情况如下: input a number:3 area of square is: 9.000000 程序中采用了第三种形式的条件编译。根据常量表达式 ( 常量R)为真或为假 ( 修改宏定义) ,进行条件编译,可输出圆面积或正方形面积。 从上述三种命令形式可以发现,条件编译的逻辑结构与程序设计中的选择结构很相似。实质上,条件编译也是一种选择结构。它根据给定的条件,从源程序段1和源程序段2中选择其中之一进行编译。 C 语言规定,条件编译中 #if后面的条件必须是常量表达式,即表达式中参加运算的量必须是常量,在大多数情况下使用由#define定义的符号常量。 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 9 页,共 14 页 - - - - - - - - - 当然,上面介绍的条件编译也可以用条件语句来实现。但是使用条件语句将会对整个源程序进行编译,生成的目标代码较长。而采用条件编译,则根据条件只编译其中的程序段 1 或程序段2,生成的目标代码较短。如果可选择编译的程序段很长,或者存在多个条件编译命令时,将大大缩短目标代码的长度。 在程序调试时,经常需要查看某些变量的中间结果。这时也可以使用条件编译,在程序中设置若干调试用的语句。例如: #define FLAG 1 #if FLAG printf(a=%d,a); #endif 用于在调试时查看变量a 的中间结果值。在调试完成时,只需把符号常量FLAG的宏定义改为 #define FLAG 0即可。 当再次编译该源程序时,这些调试用的语句就不再参加编译了。可以看出,使用条件编译省去了在源程序中增删调试语句的麻烦。并且,在程序正式投入运行后的维护期间,当需要再次调试程序时,这些调试语句还可以再次得到利用。 使用条件编译,还可以使源程序适应不同的运行环境,从而增强了程序在不同机器间的可移植性。 8.3 文件包含 所谓文件包含是指在一个文件中包含另一个文件的全部内容,使之成为该文件的一部分。这相当于是两个文件的合并。文件包含由文件包含命令#include来实现,其一般格式为: #include /*格式一 */ 或 #include 文件名 /*格式二 */ 其中“文件名”是指被包含的文件,称为头文件。头文件必须是文本文件,如C语言源程序文件等。头文件常以“.h ”为后缀 (h为 head 的缩写 ) ,但也可以是“ .c ”或其他,甚至没有后缀也是可以的。 在编译预处理时,文件包含命令的功能是将指定头文件的内容包含到该命令出现的位置处并替换此命令行。格式一和格式二的主要区别是在存放头文件的路径上。使用格式一时,预处理程序只在系统规定的目录(include子目录,由用户在设置编译环境时设置,具体设置方法见第13 章) 中去查找指定的头文件,若找不到,则出错,这称为标准方式。使用格式二时,预处理程序先在当前工作目录中寻找指定的头文件,若找不到,再按标准方式去查找。 一般来说,如果调用系统提供的标准库函数时使用格式一( 库函数相关的头文件一般放在系统规定的目录 ) ,以节省查找时间。如果要包含的是用户自己编写的头文件( 这种头文件往往放在当前工作目录) ,则一般使用格式二。 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 14 页 - - - - - - - - - 另外,格式一中只能写文件名及其后缀,不能含有其他成分,但格式二中的双撇号内可以含有路径,如: #include /*错误*/ #include C:TCF2.c /*正确*/ 在进行结构化程序设计时,文件包含是很有用的。一个大的程序可以分为多个源程序文件,由多个程序员分别编写。使用文件包含的手段,可以减少重复性的劳动,有利于程序的维护和修改,同时也是 “模块化” 设计思想所要求的。将那些公用的或常用的宏定义、函数原型、数据类型定义及全局变量的定义和声明等,组织在一些头文件中,在程序需要使用到这些信息时,就用#include命令把它们包含到所需的位置上去,从而免去每次使用它们时都要重新定义或声明的麻烦。 Turbo C系统就是这样进行的,它为用户提供了许多头文件,称为“标准头文件”。其中,stdio.h中有 EOF和 NULL宏定义及输入输出函数的原型等;math.h 中有各个数学函数的原型; io.h中有数据类型struct ftime的定义。 例 8-11 用户头文件的编写和使用。 L8_11.h 文件源代码如下 : #ifndef _L8_11_H #define _L8_11_H /*定义宏,以防止重复包含此头文件*/ #include #define ADD(a,b) (a)+(b) /*定义宏,实现两数的加法 */ #define SUB(a,b) (a)-(b) int MUL(int a,int b) /*定义函数,实现两数的乘法*/ return a*b; float DIV(float a,float b) if(b!=0) return a/b; else printf(Error! The deno cannot be zero!); #endif L8_11.c 文件源代码如下 : #include L8_11.h /*包含自定义头文件 */ main() int a,b; int sum,product; float difference,quotient; printf(Please input two numbers:); scanf(%d,%d,&a,&b); sum=ADD(a,b); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 11 页,共 14 页 - - - - - - - - - difference=SUB(a,b); product=MUL(a,b); quotient=DIV(a,b); printf(sum=%d difference=%fn,sum,difference); printf(product=%d quotient=%fn,product,quotient); 程序运行情况如下: Please input two numbers:34,12 sum=46 difference=22.000000 product=408 quotient=2.833333 对文件包含命令还要说明以下几点: (1) 一个#include命令只能包含一个头文件,若有多个文件要包含,则需用多个#include命令。 例如:如果file1.c中包含 file2.c,而file2.c中要用到file3.c的内容,则可在file1.c中用两个 #include命令进行包含,包含顺序如下: #include file3.c #include file2.c 即在包含file2.c之前先包含file3.c,所以file2.c中可以直接使用file3.c的内容,而不必再在file2.c中用#include file3.c了( 以上是假设file2.c在本程序中只被file1.c包含,而不出现在其他场合) 。 (2) 文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。 上面的问题也可以这样处理,即在file1.c中定义: #include file2.c 再在 file2.c中定义: #include file3.c 与(1) 中所述方法作用相同。 (3) 当某个头文件的内容发生变化时,意味着包含该头文件的源程序也发生变化,所以需要重新编译。 本章小结 程序的编译可分为编译预处理和正式编译两个步骤。编译预处理是在将源程序生成目标文件前对源程序的预加工。正确使用编译预处理命令可有效提高程序的开发效率。语言提供了多种预处理命令,常用的有宏定义、条件编译和文件包含。 宏定义命令为 #define ,宏定义是用一个标识符 (宏名)来代表替换文本,替换文本可以是常量、变量或表达式等。 在引用宏时将用替换文本代替宏名。宏定义还可以带有参数,引用带参宏时除了用替换文本代替宏名外,还要用实参代替形参。但带参宏的引用与函数调用有本质的区别,不可混淆。 条件编译是根据条件成立与否,选择编译源程序中满足条件的程序段,使生成的目标程序较短,减名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 12 页,共 14 页 - - - - - - - - - 少内存开销,提高程序的运行效率。而且使程序调试变得非常方便。 文件包含命令为 #include ,它可把一个或多个文件包含到另一个源文件中进行编译,结果将生成一个目标文件。这是实现结构化程序设计中“模块化”设计思想的重要手段。 正确使用编译预处理命令将有利于提高程序的可移植性、可阅读性和可维护性,也便于实现模块化程序设计。 习 题 八 一、选择题 1以下程序中的for 循环执行的次数是 。 A) 5 B) 6 C) 8 D) 9 #define N 2 #define M N+1 #define NUM (M+1)*M/2 main() int i; for(i=1;i=NUM;i+) ; printf(%dn,i); 2以下程序的输出结果是 。 A) 15 B) 100 C) 10 D) 150 #define MIN(x,y) (x)(y)?(x):(y) main() int i,j,k; i=10; j=15; k=10*MIN(i,j); printf(%dn,k); 3以下程序的输出结果是 。 A) 11 B) 12 C) 13 D) 15 #include stdio.h #define FUDGF(y) 2.84+y #define PR(a) printf(%d,(int)(a) #define PRINT1(a) PR(a); putchar(n) main() int x=2; PRINT1(FUDGF(5)*x); 4以下程序的输出结果是 。 A)320 B)900 C)9000 D)300 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 13 页,共 14 页 - - - - - - - - - #define S(r) 10*r*r main() int a=10,b=20,s; s=S(a+b); printf(%dn,s); 5以下叙述中正确的是 。 A) 用#include包含的头文件的后缀不可以是“.a”。 B) 若一些源程序中包含某个头文件;当该头文件有错时,只需对该头文件进行修改,包含此头文件的所有源程序不必重新进行编译。 C) 宏定义可以看成是一行C语句。 D) C 程序中的预处理是在编译之前进行的。 二、编程题 1请写出一个宏定义ISALPHA(C) ,用以判断C是否是字母字符,若是,得1,否则得0。 2请写出一个宏定义SWAP(t,x,y) 用以交换t 类型的两个参数x、y。提示:用复合语句的形式。 3用条件编译实现:输入一行字符,可以用两种方式输出,一种为原文输出,另一种将字母变成其后续字母,即按密码输出。 4对年份year,定义一个宏,以判别该年份是否闰年。 5求三个整数的平均值,要求用带参宏实现且把带参宏定义存放在头文件中。 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 14 页,共 14 页 - - - - - - - - -