本文最后更新于 621 天前,其中的信息可能已经有所发展或是发生改变。
预处理器
预定义符号
符号 | 示例 | 含义 |
---|---|---|
__FILE__ | "a.c" | 进行编译的源文件名 |
__LINE__ | 5 | 文件当前的行号 |
__DATE__ | "Jan 1 1999" | 文件被编译的日期 |
__TIME__ | "18.11.22" | 文件被编译的时间 |
__STDC__ | 1 | 是否遵循 ANSI C |
宏
#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)
#define name(parameter-list) stuff
其中, parameter-list 参数列表是一个逗号分隔的符号列表,它们可能出现在 stuff 中。参数列表的左括号必须与 name 紧邻。如果有空白,则被解释为 stuff 的一部分。
例如:
#define SQUARE(x) ((x) * (x))
用于对数值求值的宏定义都应该使用这种方式加上括号,避免在使用宏时,由于参数中的操作符或邻近的操作符之间不可预料的相互作用。
#define 替换
在程序中扩展#define 定义符号和宏时:
- 首先对参数进行检查,看看是否包含了任何由#define 定义的符号,如果是,它们首先被替换。
-
替换文本被插入程序中原来文本的位置,对于宏,参数名被它们的值所替代。
-
最后,再次对结果文本进行扫描,检查是否包含了任何由 #define 定义的符号,如果是,就重复上述处理过程。
这样,宏参数和#define 定义可以包含其它#define 定义的符号,但是宏不可以出现递归。
当预处理器搜索#define 定义的符号时,字符串常量的内容不进行检查。如果想把宏参数插入到字符串常量中,可以使用预处理器把一个宏参数转换成一个字符串。
#argument 这种结构被预处理器翻译为 "argument"
#define PRINT(FORMAT,VALUE) \
printf("The value of " #VALUE \
" is " FORMAT "\n", VALUE)
...
PRINT("%d", x+3);
//输出
The value of x+3 is 25
## 把位于它两边的符号连接成一个符号
#define ADD_TO_SUM(sum_number, value) \
sum ## sum_number += value
...
ADD_TO_SUM(5, 25);
最后一条语句把值25加到sum5,注意这种连接必须产生一个合法的标识符。
宏与函数
宏经常用于简单的计算,效率比函数要高,函数的参数必须声明为一种特定的类型,宏与类型无关。
无法使用函数实现:
#define MALLOC(n,type)\
((type *)malloc((n) * sizeof(type)))
宏的副作用
参数为x++
类型时,可能自加多次。同样的,以函数返回值作为参数,函数可能执行多次。
命名约定
- 把宏名字全部大写
#undef
用于移除一个宏定义
命令行定义
UNIX编译器中使用-D
选项可以完成命令行定义。例如
cc -DARRAY_SIZE=100 prog.c
UNIX编译器中使用-U
选项可以忽略符号的初始定义。
条件编译
#if constant-expression
statements
#elif constant-expression
onther statements
#else
onther statements
#endif
文件包含
库文件包含 #include <filename.h>
本地文件包含 #include "filename.h"