预处理类别
宏定义:#define
- 将文本替换为表达式或语句
条件编译:#ifdef
、#ifndef
和#if
、#elif
、#endif
- 根据标识符是否被定义选择编译代码
头文件包含:#include
- 将其他文件(通常是头文件)包含到当前文件中,以便在当前文件中使用头文件中定义的内容
预处理流程
- 预处理指令识别
- 宏替换
- 条件编译
- 头文件包含
- 行连接处理
- 宏展开和条件编译的递归处理
预处理指令识别
扫描源代码并识别以#
开头的预处理指令。
宏替换
预处理器根据宏定义将代码中的宏名称替换为指定的文本。 可以是常量替换,也可以是带参数的宏函数替换 预处理器会根据宏定义展开宏
条件编译
根据条件选择性地编译不同的代码块。
#ifdef
、#ifndef
和#if
、#elif
、#endif
头文件包含
通过#include
指令,将其他文件(通常是头文件)包含到当前文件中,以便在当前文件中使用头文件中定义的内容
预处理的行连接处理
在C语言中,行连接处理是预处理阶段的一部分,用于将一行代码书写为多行,以保持代码可读性。
行连接操作通过反斜杠字符实现。一行代码以反斜杠字符结尾时,该行代码将与下一行自动连接为一行。
换行之后的进位也会被当作空格输出出来。 行连接在预处理阶段,在编译阶段看到代码时,已经是连接在一起的一行。这种处理不会影响编译器的语义分析和中间代码。
宏展开和条件编译的递归处理
在进行宏展开和条件编译时,如果遇到新的预处理指令,预处理器会递归地处理这些指令。肯呢个会触发更多的宏展开和条件编译。
删除注释
预处理器将源代码中的注释删除,注释在预处理阶段无需保留,不会影响编译器的输出。
预编译的警告信息和错误信息
可以使用#error
和#warning
预处理指令来生成编译错误和警告信息。这些指令在预处理时发出特定的错误或警告信息,让开发者知道代码中存在的问题或需要注意的地方
#error
和#warning
指令生成的信息只会在预处理阶段发出,而不会影响到最终的目标代码,它们在编译阶段不会生成任何错误或警告信息。
查看预处理后的源文件
以肯哥用的GCC为例。
可以使用-E
选项来查看预处理后的源文件。只进行预处理操作,不进行编译、汇编和链接。将预处理后的源文件输出到标准输出流,一般是控制台。
gcc -E example.c
编译器会将预处理后的内容输出到控制台。
如果你想将预处理后的源文件保存到一个文件中,可以使用重定向操作符>
将输出重定向到一个文件中。
gcc -E example.c > preprocessed.c
上述命令会将预处理后的源文件保存到名为preprocessed.c
的文件中。
重点强调
- 宏定义的命名规范
- 宏定义与函数调用的冲突
#include
不单单是只能包含头文件:include
的本质就是纯文本包含。- 善用条件编译:在庞大工程代码的配置裁剪工作中,绝大多数的技术手段就是利用条件编译,对不同的代码选用和删除,达到代码裁剪的效果。