欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C语言:预处理

程序员文章站 2024-02-22 15:33:58
...

一.宏定义

(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 是将已经存在文件的内容嵌入到当前文件中。