![]() |
|
| 小说首页 | 言情小说 | [都市小说] | 玄幻小说 | 武侠小说 | 科幻小说 | 历史军事 | 网游小说 | 名著杂志 | 小说排行榜 | 完本小说 | 热门电影 | |
| 网站首页 > 都市小说 > C语言设计第三版 |
第33章5. 带参的宏和带参函数很相似,但有本质上的不同,除上面已谈到的各点外,把同一 表达式用函数处理与用宏处理两者的结果有可能是不同的。 【例 9.9】 main(){ int i=1; while(i<=5) printf("%d\n",SQ(i++)); } SQ(int y) { return((y)*(y)); } 【例 9.10】 #define SQ(y) ((y)*(y)) main(){ int i=1; while(i<=5) printf("%d\n",SQ(i++)); } 在例 9.9 中函数名为 SQ,形参为 Y,函数体表达式为((y)*(y))。在例 9.10 中宏名为 SQ, 形参也为 y,字符串表达式为(y)*(y))。 例 9.9 的函数调用为 SQ(i++),例 9.10 的宏调用为 SQ(i++),实参也是相同的。从输出结果来看,却大不相同。 分析如下:在例 9.9 中,函数调用是把实参 i 值传给形参 y 后自增 1。 然后输出函数值。 因而要循环 5 次。输出 1~5 的平方值。而在例 9.10 中宏调用时,只作代换。SQ(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 值再自增 1 变为 6,不再满足循环条 件,停止循环。 从以上分析可以看出函数调用和宏调用二者在形式上相似,在本质上是完全不同的。 6. 宏定义也可用来定义多个语句,在宏调用时,把这些语句又代换到源程序内。看下 面的例子。 【例 9.11】 #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=%d\nsb=%d\nsc=%d\nvv=%d\n",sa,sb,sc,vv); } 程序第一行为宏定义,用宏名 SSSV 表示 4 个赋值语句,4 个形参分别为 4 个赋值符左部 的变量。在宏调用时,把 4 个语句展开并用实参代替形参。使计算结果送入实参之中。 9.3 文件包含 文件包含是 C 预处理程序的另一个重要功能。 文件包含命令行的一般形式为: #include"文件名" 在前面我们已多次用此命令包含过库函数的头文件。例如: #include"stdio.h" #include"math.h" 文件包含命令的功能是把指定的文件插入该命令行位置取代该命令行,从而把指定的文件和 当前的源程序文件连成一个源文件。 在程序设计中,文件包含是很有用的。一个大的程序可以分为多个模块,由多个程序员 分别编程。有些公用的符号常量或宏定义等可单独组成一个文件,在其它文件的开头用包含 命令包含该文件即可使用。这样,可避免在每个文件开头都去书写那些公用量,从而节省时 间,并减少出错。 对文件包含命令还要说明以下几点: 1. 包含命令中的文件名可以用双引号括起来,也可以用尖括号括起来。例如以下写法 都是允许的: #include"stdio.h" #include 但是这两种形式是有区别的:使用尖括号表示在包含文件目录中去查找(包含目录是 由用户在设置环境时设置的),而不在源文件目录去查找; 使用双引号则表示首先在当前的源文件目录中查找,若未找到才到包含目录中去查 找。用户编程时可根据自己文件所在的目录来选择某一种命令形式。 2. 一个 include 命令只能指定一个被包含文件,若有多个文件要包含,则需用多个 include 命令。 3. 文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。 9.4 条件编译 预处理程序提供了条件编译的功能。可以按不同的条件去编译不同的程序部分,因而产 生不同的目标代码文件。这对于程序的移植和调试是很有用的。 条件编译有三种形式,下面分别介绍: 1. 第一种形式: #ifdef 标识符 程序段 1 #else 程序段 2 #endif 它的功能是,如果标识符已被 #define 命令定义过则对程序段 1 进行编译;否则对 程序段 2 进行编译。如果没有程序段 2(它为空),本格式中的#else 可以没有,即可以写 为: #ifdef 标识符 程序段 #endif 【例 9.12】 #define NUM ok main(){ struct stu { int num; char *name; char sex; float score; } *ps; ps=(struct stu*)malloc(sizeof(struct stu)); ps->num=102; ps->name="Zhang ping"; ps->sex='M'; ps->score=62.5; #ifdef NUM printf("Number=%d\nScore=%f\n",ps->num,ps->score); #else printf("Name=%s\nSex=%c\n",ps->name,ps->sex); #endif free(ps); } 由于在程序的第 16 行插入了条件编译预处理命令,因此要根据 NUM 是否被定义过来决定 编译那一个 printf 语句。而在程序的第一行已对 NUM 作过宏定义,因此应对第一个 printf 语句作编译故运行结果是输出了学号和成绩。 在程序的第一行宏定义中,定义 NUM 表示字符串 OK,其实也可以为任何字符串,甚至不 给出任何字符串,写为: #define NUM 也具有同样的意义。只有取消程序的第一行才会去编译第二个 printf 语句。读者可上机试作。 2. 第二种形式: #ifndef 标识符 程序段 1 #else 程序段 2 #endif 与第一种形式的区别是将 “ifdef” 改为“ifndef” 。它的功能是,如果标识符未被 #define 命令定义过则对程序段 1 进行编译,否则对程序段 2 进行编译。这与第一种形式的 功能正相反。 3. 第三种形式: #if 常量表达式 程序段 1 #else 程序段 2 #endif 它的功能是,如常量表达式的值为真(非 0),则对程序段 1 进行编译,否则对程序段 2 进行编译。因此可以使程序在不同条件下,完成不同的功能。 【例 9.13】 #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: %f\n",r); #else s=c*c; printf("area of square is: %f\n",s); #endif } 本例中采用了第三种形式的条件编译。在程序第一行宏定义中,定义 R 为 1,因此在条 件编译时,常量表达式的值为真,故计算并输出圆面积。 上面介绍的条件编译当然也可以用条件语句来实现。 但是用条件语句将会对整个源程序 进行编译,生成的目标代码程序很长,而采用条件编译,则根据条件只编译其中的程序段 1 或程序段 2,生成的目标程序较短。 |
| 第33章_C语言设计第三版在线阅读_谭浩强 站内所有资源均收集于互联网,其版权属原作者所有。如有问题请及时与我们联系。 [xg-42 yz- h-7]] All Rights Reserved 京ICP备10019856号 手机版 创建缓存:82faf 大小:8K 缓存保留时间:4320分钟 |