预处理器怎样处理代码
预处理器的作用是在编译器处理 C 代码前,先对源码进行一系列必要的转换。这些转换可以引入代码正常编译所需要的各个依赖项,动态修改代码以适应不同的编译环境,甚至根据需要自动生成部分 C 代码。对预处理器的合理使用,可以提高程序的可配置性。
在gcc中,通过 -E 参数生成预处理过后的文件。
预处理器通过以下步骤完成对代码的预处理:
1.删除源代码中的所有注释;
2.处理所有宏定义(#define),并进行展开和替换;
3.处理所有条件预编译指令(如 #if、#elif),仅保留符合条件的代码;
4.处理文件包含预编译指令(#include),将被包含文件的内容插入到该指令的所在位置;
5.处理其他可以识别的预处理指令(如 #pragma);
6.添加其他具有辅助性功能的注释信息。
一、宏
除去删除注释外,预处理器对代码的处理很大一部分是对于宏的处理。
1.宏函数
宏函数的运作方式与 C 函数有很大的差别,宏函数在被调用时,仅会做源代码文本上的替换,在处理宏函数参数以及宏函数体内的多行语句时,通常使用 do…while 语句等技巧,来对参数、返回值与函数体进行“封装”。
2.使用技巧
1.为宏函数的返回值添加括号
宏被展开后,printf语句变为如下形式:printf("%d", 3 * 1 + 2 * 2);与想象中的完全不同,对这个宏加上括号后:(1 + x * x),结果才符合预期。
2.为函数的参数添加括号
宏被展开后,printf语句变为如下形式:printf("%d", (1 + 1 + 2 * 1 + 2));和想象中的完全不同,对参数加上括号后:(1 + (x) * (x)),结果才符合预期。
3.警惕宏函数导致的多次副作用
宏展开后,printf语句变为如下形式:printf("%d", (1 + (++i) * (++i)));和想象中的完全不同。
必须要注意,宏函数和 C 函数的调用是完全不同的两种方式。前者是文本上的直接替换,不会产生任何栈帧,替换后的新代码,可能计算逻辑已经发生了变化,从而导致计算错误。
4.定义完备的多语句宏函数
这个宏被展开后没有什么变化,但是由于 if 语句没有括号,所以在任何情况下,最后的 world 都会被打印出来,原因也是因为宏只做了简单的文本替换,对于多行代码的宏函数,可以通过 do-while 语句进行处理:
do {
printf("Hello, ");
printf("world!");
} while(0)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix