Gcc 编译的背后--预处理

来源:互联网 发布:sql 字段累加 编辑:程序博客网 时间:2024/05/16 12:47

预处理

简述

预处理是 C 语言程序从源代码变成可执行程序的第一步,主要是 C 语言编译器对各种预处理命令进行处理,包括头文件的包含、宏定义的扩展、条件编译的选择等。

以前没怎么“深入”预处理,脑子对这些东西总是很模糊,只记得在编译的基本过程(词法分析、语法分析)之前还需要对源代码中的宏定义、文件包含、条件编译等命令进行处理。这三类的指令很常见,主要有 #define#include和 #ifdef ... #endif,要特别地注意它们的用法。

#define 除了可以独立使用以便灵活设置一些参数外,还常常和 #ifdef ... #endif 结合使用,以便灵活地控制代码块的编译与否,也可以用来避免同一个头文件的多次包含。关于 #include 貌似比较简单,通过 man 找到某个函数的头文件,复制进去,加上 <> 就好。这里虽然只关心一些技巧,不过预处理还是隐藏着很多潜在的陷阱(可参考《C Traps & Pitfalls》)也是需要注意的。下面仅介绍和预处理相关的几个简单内容。

打印出预处理之后的结果

$ gcc -E hello.c

这样就可以看到源代码中的各种预处理命令是如何被解释的,从而方便理解和查错。

实际上 gcc 在这里调用了 cpp(虽然通过 gcc -v 仅看到 cc1),cpp 即 The C Preprocessor,主要用来预处理宏定义、文件包含、条件编译等。下面介绍它的一个比较重要的选项 -D

在命令行定义宏

$ gcc -Dmacro hello.c

这个等同于在文件的开头定义宏,即 #define macro,但是在命令行定义更灵活。例如,在源代码中有这些语句。

#ifdef DEBUGprintf("this code is for debugging\n");#endif

如果编译时加上 -DDEBUG 选项,那么编译器就会把 printf 所在的行编译进目标代码,从而方便地跟踪该位置的某些程序状态。这样 -DDEBUG 就可以当作一个调试开关,编译时加上它就可以用来打印调试信息,发布时则可以通过去掉该编译选项把调试信息去掉。

原创粉丝点击