预编译头文件的实际工作原理

Dmi*_*ich 1 c++ precompiled-headers visual-c++

我所有的问题都与 vc++ 编译器有关,但我猜其他 c++ 编译器具有相同的行为。

  1. 预编译头文件是与预处理器相关的内容还是与编译过程有关?或两者?我有几个猜测:
    • PCH 引擎只扩展 MACRO 定义和嵌套头并将它们转换为二进制格式(pch 文件)。在这种情况下,所有源文件(我的意思是 cpp/hpp 也可能包含在 PCH 中)将在项目中的每个源文件中重新编译。或不?
    • 所有源文件将只编译一次并拉入单个 obj 文件?例如,在这个例子中,变体库会被编译多少次?即只有一次 - 在 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"
...
Run Code Online (Sandbox Code Playgroud)
  1. 我应该在预编译头文件中放入哪些文件?我想这是在项目中随处使用并且很少改变的东西。图书馆怎么样,例如提升?我们只在少数源文件中使用 boost,我们应该把它放在 PCH 中吗?

Sam*_*hik 6

我对 VC++ 的内脏没有特别的了解。然而,有了一些编译器设计和理论的知识,这些所谓的“预编译头”就不仅仅是经典编译器设计的初始词法分析和标记化阶段的结果。

考虑一个包含以下内容的简单头文件:

#ifdef FOO
#define BAR 10
#else
#undef FOOBAR
class Foo {
public:
     void bar();
};
#include "foobar.h"
#endif
Run Code Online (Sandbox Code Playgroud)

您必须了解使用所谓的“预编译”头文件的效果必须与使用头文件的效果相同。

在这里,你真的不知道这个头文件要做什么。这一切都取决于实际包含头文件时定义的预处理器宏。你不知道这个头文件将定义哪些宏。你不知道这个头文件将取消定义哪些宏。你不知道这个头文件会包含哪些其他头文件。你真的知道的不多,这里。

从概念上讲,要“预编译”头文件,您唯一可以做的就是预解析它。将语言的各个元素、各个关键字(如“#ifdef”、“class”和所有其他内容)转换为单独的二进制标记。删除任何评论,空格等...

编译传统语言的第一阶段涉及将纯文本源解析为内部语言元素。词法分析和标记化阶段。在解析了各个语言元素之后,将尝试弄清楚如何将生成的解析源代码转换为对象模块。这就是编译器 99% 的工作所在。最初的词法分析阶段并不是很多,但这几乎是“预编译”源代码并保存标记化源的内部二进制表示的全部内容,以便可以跳过此阶段,当实际代码使用“预编译”源进行编译。

我假设 VC++ 对预编译头文件的内容几乎没有任何限制。但是,如果有一些限制——比如,预编译头不能有任何条件预处理器指令(ifdef/ifndef),除了经典的守卫——那么就有可能做更多的工作来生成预编译头,并节省一个多一点工作,在这里。对预编译头文件内容的其他限制也可能导致一些附加功能被转移到预编译阶段。