![嵌入式C语言自我修养:从芯片、编译器到操作系统](https://wfqqreader-1252317822.image.myqcloud.com/cover/248/37669248/b_37669248.jpg)
4.2 预处理过程
为了方便编程,编译器一般为开发人员提供一些预处理命令,使用#标识。我们常见的预处理命令如下。
● 头文件包含:#include。
● 定义一个宏:#define。
● 条件编译:#if、#else、#endif。
● 编译控制:#pragma。
编译器提供的这些预处理命令,大大方便了程序的编写:通过头文件包含可以实现模块化编程;使用宏可以定义一个常量,提高程序的可读性;通过条件编译可以让代码兼容不同的处理器架构和平台,以最大限度地复用公用代码。通过#pragma预处理命令可以设定编译器的状态,指示编译器完成一些特定的动作。
● #pragma pack([n]):指示结构体和联合成员的对齐方式。
● #pragma message("string"):在编译信息输出窗口打印自己的文本信息。
● #pragma warning:有选择地改变编译器的警告信息行为。
● #pragma once:在头文件中添加这条指令,可以防止头文件多次编译。
预处理过程,其实就是在编译源程序之前,先处理源文件中的各种预处理命令。编译器是不认识预处理指令的,在编译之前不先把这些预处理命令处理掉,编译器就会报错。预处理主要包括以下操作。
● 头文件展开:将#include包含的头文件内容展开到当前位置。
● 宏展开:展开所有的宏定义,并删除#define。
● 条件编译:根据宏定义条件,选择要参与编译的分支代码,其余的分支丢弃。
● 删除注释。
● 添加行号和文件名标识:编译过程中根据需要可以显示这些信息。
● 保留#pragma命令:该命令会在程序编译时指示编译器执行一些特定行为。
一个源程序在预处理前后有什么变化呢?我们写了一个测试程序,分别使用预处理命令去定义一些宏和条件编译。
![](https://epubservercos.yuewen.com/1B291C/19938711108152406/epubprivate/OEBPS/Images/40856_147_1.jpg?sign=1738849814-JHeytsMkOdz4C7Wi411YsmUV8U7BjOMN-0-9289274a6a5ef6c43b7f392a33531612)
![](https://epubservercos.yuewen.com/1B291C/19938711108152406/epubprivate/OEBPS/Images/40856_148_1.jpg?sign=1738849814-dw7TM4PgpAEG88btuEglb8tiwhcYS1fg-0-ed3c8c4748251a5c5120fc289abd27bf)
对上面的C程序只作预处理操作,不编译,将输出的信息重定向到main.i文件。
![](https://epubservercos.yuewen.com/1B291C/19938711108152406/epubprivate/OEBPS/Images/40856_148_2.jpg?sign=1738849814-DvTgN2Xe8UTUkPdC5s6eti7f5QW0OeFK-0-f70134f74bc455166d9b23df7140e718)
![](https://epubservercos.yuewen.com/1B291C/19938711108152406/epubprivate/OEBPS/Images/40856_149_1.jpg?sign=1738849814-NuNJMwppUNblTAC8ispKEdqlvHGCpX2M-0-972344316e64cc968cf52795c48801c6)
通过预处理前后源文件的变化对比,我们可以看到:当预处理器遇到#include命令时,会直接将包含的头文件内容展开,并删除#include;当遇到#define宏时,执行同样的操作。当遇到条件编译指令时,会根据开发者定义的宏标记,选择要参与编译的代码部分,其余部分删除,经过预处理后,#pragma保留,指示编译器在后续的编译阶段执行一些特定的操作。继续编译预处理后的C程序,在编译信息提示窗口里,我们会看到自己添加的编译提示信息。
![](https://epubservercos.yuewen.com/1B291C/19938711108152406/epubprivate/OEBPS/Images/40856_149_2.jpg?sign=1738849814-zDDKov88EvCBoaVrGgxCtE8cGa8P4G3J-0-d5fec8d65bc3f1540c4aac52bd5eb0d8)