C 语言 - 预处理器
C 预处理器(Preprocessor)不是编译器的一部分,而是编译过程中的一个单独步骤。简单来说,C 预处理器只是一个文本替换工具,它指示编译器在实际编译之前进行所需的预处理。
在 C 语言中,所有预处理器命令(Directive)均以井号(#
)开头。它必须是第一个非空白字符,换句话说,预处理器指令 #
前面可以有空白符,但是为了可读性,不建议在 #
前面添加空白符。
下表列出了 C 语言中常见且重要的预处理器指令。
序号 | 指令 | 说明 |
---|---|---|
1 | #define | 替代预 处理器宏,或者叫“宏定义”。 |
2 | #include | 引入一个头文件。 |
3 | #undef | 取消定义预处理器宏。 |
4 | #ifdef | 如果定义了该宏,则返回 true。 |
5 | #ifndef | 如果未定义该宏,则返回 true。 |
6 | #if | 测试编译时条件是否为真。 |
7 | #else | #if 条件的另一个分支。 |
8 | #elif | 相当于将 #else 和 #if 写在一条语句中。 |
9 | #endif | 结束 #if 预处理器。 |
10 | #error | 在 stderr 上打印错误消息。 |
11 | #pragma | 使用标准方法向编译器发出特殊命令。 |
初识预处理器
下面通过一些简单的示例,带你了解 C 语言预处理器的常见用法。
#define MAX_ARRAY_LENGTH 20
上述指令告诉 C 预处理器在编译时将代码中的 MAX_ARRAY_LENGTH
实例替换为数字 20
。对常量使用 #define
可以提高代码可读 性,例如在这个示例中,你可以很清晰地知道数字 20 表示的是数组长度。
#include <stdio.h>
#include "myheader.h"
上述指令告诉 C 预处理器从系统库获取头文件 stdio.h 并将其内容插入到当前源文件中,第二行告诉 C 预处理器从本地目录获取头文件 myheader.h 并将其内容插入到当前源文件中。
#undef FILE_SIZE
#define FILE_SIZE 42
上述指令告诉 C 预处理器取消已经存在的 FILE_SIZE
宏定义,然后将其重新定义为 42。
#ifndef MESSAGE
#define MESSAGE "You wish!"
#endif
上述指令告诉 C 预处理器如果 MESSAGE
宏还没定义,则定义该宏。
#ifdef DEBUG
/* Your debugging statements here */
#endif
上述指令告诉 C 预处理器如果定义了 DEBUG
,就处理该宏所包含的语句。例如,如果你在编译时将 -DDEBUG
标志传递给 gcc 编译器,就会定义 DEBUG
宏。通过这种方式,你可以在编译期间动态打开和关闭调试。
预定义宏
ANSI C 预定义了一些宏,它们使用双下划线包裹。你可以在你的 C 程序中使用它们。但需要注意,请不要直接修改这些预定义的宏,例如取消定义或重新定义它们。
序号 | 宏 | 说明 |
---|---|---|
1 | __DATE__ | 当前日期,以 MMM DD YYYY 格式保存的字符串。 |
2 | __TIME__ | 当前时间,以 HH:MM:SS 格式保存的字符串。 |
3 | __FILE__ | 当前文件名,以字符串格式保存。 |
4 | __LINE__ | 当前代码行号,以十进制常量形式保存。 |
5 | __STDC__ | 当编译器符合 ANSI 标准时定义为 1。 |
一起来看看下面的例子:
#include <stdio.h>
int main()
{
printf("File :%s\n", __FILE__ );
printf("Date :%s\n", __DATE__ );
printf("Time :%s\n", __TIME__ );
printf("Line :%d\n", __LINE__ );
printf("ANSI :%d\n", __STDC__ );
return 0;
}
将上述代码保存为 test.c 文件,编译并运行程序,结果如下:
File :test.c
Date :Nov 19 2023
Time :14:11:37
Line :8
ANSI :1