C语言:预处理
一.宏定义
(1)数值宏定义
const这个关键字修饰的数据是有类型的,而define宏定义的数据是没有类型的。因此在定义一些宏常数的时候用const代替,编译器会给const修饰的只读变量做类型校验,减少错误的可能。
(2)字符串宏常量
除了定义宏常数之外,经常还用来定义字符串,尤其是路径。
#define ENG_PATH_1 E:\English\listen_to_this\listen_to_this_3
#define ENG_PATH_2 " E:\English\listen_to_this\listen_to_this_3"
#define ENG_PATH_1 E:\English\listen_to_this\listen\
_to_this_3
注意:反斜杠作为接续符时,在本行其后面不能有任何字符,空格都不行,所以最后一个反斜杠才是接续符。
(3)用define 宏定义注释符号“?”
例如:
#define BSC//
#define BMC/*
#define EMC*/
(D)BSC my single -line comment
(E)BMC my multi -line comment EMC
(D)(E)都是错误的,因为注释先于预处理指令被处理,当前两行被展开成“//…”或“/…/”时,注释已经处理完毕,此时再出现“//…”或“/…/”自然产生错误。因此试图用宏开始或者结束一段注释都是不行的。
(4)用define 宏定义表达式
例如:定义一年有多少秒
#define SEC_A_YEAR (60*60*24*365)
这个定义是错误的,因为并没有考虑到16位系统下把这样一个数赋给整型变量的时候可能会发生溢出,一年有多少秒,不可能是负数。
可以修改一下得:但是此时有出现一个问题是这里的括号到底需不需要呢?
#define SEC_A_YEAR (606024*365)UL
再举一个例子:
#define SQR(x) x*x
此时假设x的值为10,SQR(x)被替换后变成10 * 10.没有问题。
假设x的值是一个表达式10+1,SQR(x)被替换后变成10+1*10+1。问题来了,这并不是想要的结果。
#define SQR(x) ( x)*(x)
此时这个代码没有问题吗?不尽然吧!
再举一个例子:
#define SUM(x) (x)*(x)
假如x的值是一个表达式53,而代码又写为SUM(x)SUM(x),替换后变成(53)+(53)(53)+(5*3),此时得到的结果与想要的结果也不相同。
所以最外层的括号最好别省了
注意:函数宏被调用时是以实参代替形参,而不是“值传送”。
规则1 的宏定义只能扩展为用大括号括起来的初始化常量,小括号括起来的表达式,类型限定符,存储类标识符或者do-while-zero结构。
注意:宏语句的结尾必须省略分号。
规则2 函数宏的调用不能缺少参数,如果此函数宏有参数的话。
规则3 传递给函数宏的参数不能包含看似预处理指令的标记。
规则4 在定义函数宏时,每个参数实例都应该以小括号括起来,除非她们作为#或##的操作数。
例如:
#define abs(x)((x)>=0)?(x):(-x))
不能定义为:
#define abs(x) (((x) >=0)?x :-x)
因为如果这样定义的话z=abs(a-b);将会给出z=((a-b>=0)?a-b:a-b);子表达式-a-b相对于(-a)-b)而不是希望的-(a-b)。
规则5 define的预处理操纵阀只能使用两种标准形式:
defned (identfier)
defined identifer
(5)宏定义的空格
#define SUM (x) (x)+(x) 这并不是定义函数宏SUM(x),编译器会认为 这是定义了一个宏:SUM,其代表的是(x) (x)+(x).其关键问题就在于SUM后面的空格。
二.文件包含
(1)#include <filename>
表示预处理到系统规定的路径中去获得这个文件(即C编译系统提供的并存在指定子目录下的头文件)。
(2)#include "filename"
双引号表示预处理应该在当前目录中查找文件名为filename的文件,若没有找到,则系统指定的路径信息搜索其他目录。
#Include 是将已经存在文件的内容嵌入到当前文件中。
上一篇: C语言--预处理