gcc预编译头文件的怪异行为
Weird Behavior with gcc precompiled headers
我在让预编译的头文件工作时遇到了麻烦,所以我提出了以下最小工作示例。
这是头文件foo.h
#include <iostream>
using namespace std;
void hello() {
cout << "Hello World" << endl;
}
我编译这个作为g++ -c foo.h
给我一个编译头foo.gch
。我希望当我编译以下包含foo.h
的源文件时,它应该选择头文件foo.h.gch
,并且我很好。
// test.cpp
#include <cstdio> // Swap ordering later
#include "foo.h" // ------------------
int main() {
hello();
}
但令人惊讶的是,这不是使用foo.h.gch
编译,而是使用foo.h
。为了验证,您可以将其编译为g++ -H test.cpp
但是,如果我按如下方式更改包含的头文件的顺序:
// test.cpp
#include "foo.h" // ------------------
#include <cstdio> // Ordering swapped
int main() {
hello();
}
现在,如果我使用g++ -H test.cpp
编译,它从foo.h.gch
编译,哇!
所以我想知道这是否是GCC中的一个bug,或者我们应该使用这样的预编译头?
对于GCC,预编译头文件只有在仅头文件,并且它们首先包含(没有任何先前的头文件)时才能工作。
这个答案更能解释为什么会这样。另请参阅GCC文档中的预编译头文件章节,其中说:
- 一次编译只能使用一个预编译头文件。
- 一旦看到第一个C标记,就不能使用预编译头文件。
顺便说一句,预编译一些大的头文件(特别是在c++中)是不值得的。YMMV .
简而言之,预编译头文件的工作原理如下:
当你请求创建一个'。Pch’文件,编译器会像往常一样处理源文件。当它这样做时,它的内部结构(主要是名称表和所有相关数据)被填充。最后,生成这些内部结构的快照,并将其保存到。pch的文件。
稍后,当编译包含头文件的源文件时,'。. Pch '文件存在时,编译器可以省略头文件的昂贵处理,并从'. Pch '文件加载可用快照。
显然,这可以在不影响语义的情况下完成,只有在:
- 包含指令排在其他指令之前;
- 编译器选项是相同的。
包含指令之前的任何内容都可以:
- 为编译器的内部数据结构添加一些东西;
- 影响头文件的处理;
- 改变实体之间的关系。
因此,在这种情况下,加载内部数据结构的快照将是错误的,因为不能保证它将使这些结构保持与标头正常处理后相同的状态。
来自GCC手册页:
一旦看到第一个C标记,就不能使用预编译的头文件。
所以在你的预编译头文件中包含<cstdio>
或者首先包含它是可以工作的
- 使用 Makefile 中的头文件编译 Pybind (不使用 cmake)
- 如何使用命令提示符、记事本和 MinGW 使用主文件、头文件和实现文件编译C++程序?
- 无论如何可以将webm / mp4文件编译/记忆为.exe程序吗?(C++)
- 从生成文件编译错误:"Unable to open output file" ..."No such file or directory"
- 如何使用 GLFW 预编译的二进制文件编译 Visual Studio 2019 发布版本
- Arduino IDE中自定义库类的.h文件编译错误的原因是什么
- makefile和错误将与大型项目分开的文件编译
- 如何使用生成文件编译具有多个目录的 c++ 项目
- 我可以将Visual Studio 2015头文件编译成dll并在VS2013中使用它吗?
- 使用Bazel将C 文件编译为python.h
- 使用 .a 文件编译简单的C++文件
- OpenCV 3.2 文件编译
- 如何从多个 cpp 文件编译 WebAssembly
- 从多个文件编译可以"undefined reference"
- 使用静态依赖性为共享二进制文件编译语法需要更加清晰
- 将Gsoap Src文件编译到我的项目中
- 如何用多个文件编译make下的dlib
- 字段的类型不完整,从多个文件编译
- 强制将特定文件编译为Objective-C/文件类型,但将整个项目编译为Objective C++
- OpenGLES 标头(包括 Availability.h)可防止 CPP 文件编译