我所有的问题都与 vc++ 编译器有关,但我猜其他 c++ 编译器也有相同的行为。
- 预编译头文件是与预处理器相关的东西还是与编译过程有关?或两者?我有几个猜测:
- PCH-engine 仅扩展宏定义和嵌套 header 并将它们转换为二进制格式(pch 文件)。在这种情况下,所有源文件(我的意思是 cpp/hpp 也可能包含在 PCH 中)将在项目中的每个源文件中重新编译。还是不行?
- 所有源文件将只编译一次并拉入单个 obj 文件?比如这个例子中会编译多少次变体库? IE。只有一次 - 在 PCH 中或两次 - 不在 PCH 中但在两个 *.cpp 文件中或三次 - 在 PCH 和两个 *.cpp 文件中?为什么?
//stdafx.h
#include <boost/variant/variant.hpp>
//test1.cpp
#include "stdafx.h"
#include <boost/variant/variant.hpp>
...
//test2.cpp
#include "stdafx.h"
...
- 我应该将哪些文件放入预编译头文件中?我想这是在项目中到处使用并且很少改变的东西。图书馆呢,例如 boost?我们只在少数源文件中使用 boost,我们应该把它放在 PCH 中吗?
最佳答案
我对 VC++ 的内部结构没有特别的了解。然而,如果对编译器设计和理论有所了解,那么这些所谓的“预编译头文件”只不过是经典编译器设计的初始词法分析和标记化阶段的结果。
考虑一个包含以下内容的简单头文件:
#ifdef FOO
#define BAR 10
#else
#undef FOOBAR
class Foo {
public:
void bar();
};
#include "foobar.h"
#endif
您必须明白,使用所谓的“预编译”头文件的效果必须与使用头文件原样相同。
在这里,你真的不知道这个头文件要做什么。这完全取决于实际包含头文件时定义的预处理器宏。你不知道这个头文件会定义哪些宏。您不知道这个头文件将取消定义哪些宏。你不知道这个头文件还会包含哪些其他头文件。在这里,您真的了解不多。
从概念上讲,要“预编译”头文件,您唯一可以做的就是预解析它。将语言的各个元素、各个关键字(如“#ifdef”、“class”和所有其他关键字)转换为各个二进制标记。删除任何注释、空格等...
编译传统语言的第一阶段涉及将纯文本源解析为内部语言元素。词法分析和标记化阶段。在解析了各个语言元素之后,将尝试弄清楚生成的、解析后的源代码应该如何转化为目标模块。这就是编译器 99% 的工作所在。最初的词法分析阶段并不多,但这几乎是您“预编译”源代码并保存标记化源的内部二进制表示的全部内容,因此可以跳过此阶段,当实际代码使用“预编译”源代码进行编译。
我假设 VC++ 对预编译头文件的内容几乎没有限制,甚至根本没有限制。但是,如果有一些限制——比如,预编译头文件不能有任何条件预处理器指令(ifdef/ifndef),除了经典的守卫——那么就可以做更多的工作来生成预编译头文件,并保存一个在这里做更多的工作。对预编译 header 内容的其他限制也可能导致一些额外的功能被转移到预编译阶段。
关于c++ - 预编译 header 的实际工作原理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36499328/