标准C程序设计(十)

20 篇文章 0 订阅
 14 预处理器
    14.1  预处理器
     预处理器是一个程序,在源代码通过编译器之前,他先对源代码进行处理。他是在称为预处理器命令行或指令的控制下操作。预处理器指令放在源程序的main函数之前。在源代码通过编译器之前,由预处理器检查所有预处理指令。如果有预处理指令,则采取相应的动作,然后再把源程序交给编译器。
表14.1 预处理指令
指令作用
#define定义一个宏替换
#undef取消一个宏定义
#ifdef测试某个宏已定义
#ifndef测试某个宏未定义
#include指定要包含的文件
#if测试一个编译时条件
#else当#if测试失败时,指定另一个测试
#endif表示#if的结束
这些指令分为三类:
  1. 宏替换指令
  2. 文件包含指令
  3. 编译器控制指令
      14.2 宏替换指令
宏替换是程序中的标识符被预定义的字符串取代的过程。一般形式:#define identifier string
如果该语句位于程序的开头,那么预处理器把源代码中每个identifier都用string来替代。关键字#define位于该行的第一列,后面跟identifier和string,他们相互之间至少有一个空格。注意,该定义不以分号结尾。
      14.2.1 简单宏替换
通常用于定义常量。如:#define  PI  3.14159
将把程序中所有的PI都替换为3.14159(从宏定义行开始直到程序结尾)。但是,字符串中的宏不会被替换。如下面两行语句:
area = PI * r * r;printf("PI = %f", PI);
预处理后,上面两行语句变成:area = 3.14159 * r * r;printf("PI = %f", 3.14159);
宏定义还可以包含表达式,但当我们使用表达是替换时,应小心防止意外的计算顺序。如下:
#define   D    45 - 22
#define   A    78 + 32
计算 ratio = D / A;经过预处理,结果为: ratio = 45 - 22 / 78 + 32;
这显然与所期望的表达式不同,通过使用括号定义可得正确结果: 
#define   D    (45 - 22)
#define   A    (78 + 32)
所以为宏定义的表达式使用括号是明智之举。正如前面所介绍的那样,对所有已定义的宏,预处理器都将执行 文本替换,这就解释了为什么#define语句不能以分号结尾.(分号也会参与替换)
        14.2.2 含参数的宏
预处理器允许使用更复杂的替换形式:#define   identifier(f1, f2, ..., fn)    string
注意,在宏identifier与左括号之间没有空格。
含参数的替换称为宏调用(类似于函数调用)。当调用宏时,预处理器将替换该字符串,即用实参替换形参。因此,字符串就像一个模板。示例如下:
#define CUBE(x)   (x * x * x)
如果在程序中出现语句:volume = CUBE(side);经过预处理后,volume = (side * side * side);
如果volume = CUBE(a + b);经过预处理后,volume = (a + b * a + b * a + b);
这显然不是我们想要的结果。所以要记得为每个形参和整个string加括号。
volume = CUBE( (a)  + (b) );
下面是一些常用的带形参的宏定义:
#define          MAX(a, b)     (((a) > (b) ) ? (a) : (b))   
#define          MIN(a, b)      (((a) < (b) ) ? (a) : (b))
#define          ABS(x)          (((x) > 0) )  ? (x) : (-x))
        14.2.3 宏嵌套
我们可以再宏的定义中使用另一个宏。示例如下:
#define          SQUARE(x)          ((x) * (x))
#define          CUBE(x)               (SQUARE(x) * (x))
#define          SIXTH(x)          (CUBE(x) * CUBE(x))
预处理器将扩展每个#define宏,直到文本中不再有宏为止。如,最后一个宏定义的第一次扩展:
((SQUARE(x) * (x)) * (SQUARE(x) * (x)))
由于SQUARE(x) 仍然是一个宏,因而进一步扩展:
((((x) * (x)) * (x)) * (((x) * (x)) * (x)))
一个宏还可以用做另一个宏的参数。如我们前面定义:
#define          MAX(a, b)     (((a) > (b) ) ? (a) : (b))   
我们可以通过嵌套来得出x,y,z三者最大值。MAX(x, MAX(y,z));
        14.2.4 取消宏定义
对于已经定义的宏,可以使用后面语句取消宏定义:#undef    identifier
        14.3 文件包含
  • 第一种形式如:#include  "filename"
其中,filename为含有所需宏定义或函数的文件名。此时,预处理器把filename的整个内容插入到程序的源代码之中。当filename包含在双引号中时,首先从当前目录中查找该文件,然后再在标准目录中查找。
  • 第二种形式如:#include  <filename>
在这种情况下,只在标准目录中查找该文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值