gcc 预编译的奇怪行为 headers
Weird Behavior with gcc precompiled headers
我在让 pre-compiled header 工作时遇到了麻烦,所以我想出了以下 minimal-working-example.
这是 header 文件 foo.h
#include <iostream>
using namespace std;
void hello() {
cout << "Hello World" << endl;
}
我将其编译为 g++ -c foo.h
给我编译的 header foo.gch
。我希望当我编译以下包含 foo.h
的源文件时,它应该选择 header 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
但是,如果我按如下方式更改包含的 header 文件的顺序:
// test.cpp
#include "foo.h" // ------------------
#include <cstdio> // Ordering swapped
int main() {
hello();
}
现在,如果我使用 g++ -H test.cpp
编译,它会从 foo.h.gch
编译,哇!
所以我想知道这是 GCC 中的错误还是我们应该像那样使用 pre-compiled header?无论哪种情况,我都认为了解它很有用..
使用 GCC,预编译的 headers 工作 仅 如果它们是 仅 header,并且如果它们首先包含在内(没有任何先前的 header)。
This answer 更详细地解释了为什么会这样。
另见 GCC 文档的 Precompiled headers 章节,其中说:
- Only one precompiled header can be used in a particular compilation.
- A precompiled header can't be used once the first C token is seen.
顺便说一句,pre-compiling 一些大的 header(特别是在 C++ 中)可能不值得付出努力。 YMMV.
来自 GCC manual pages:
A precompiled header can't be used once the first C token is seen.
因此,在您的预编译 header 中包含 <cstdio>
或首先包含它都可以。
简而言之,预编译的 header 是这样工作的:
当您请求创建“.pch”文件时,编译器会照常处理源文件。在这样做的同时,它的内部结构(主要是名称表和所有相关数据)被填充。最后,它对这些内部结构进行快照并将其保存到“.pch”文件中。
稍后,在编译包含 header 且存在“.pch”文件的源文件时,编译器可以省略 header 文件的昂贵处理并加载 ready-for-use 取而代之的是 '.pch' 文件的快照。
显然,只有在以下情况下才能在不影响语义的情况下完成此操作:
- 包含指令先于其他;
- 编译器选项相同。
包含指令之前的任何内容都可以:
- 向编译器的内部数据结构添加一些内容;
- 影响header文件的处理;
- 改变那里描述的实体之间的关系。
因此,在这种情况下,加载内部数据结构的快照将是错误的,因为无法保证它会使这些结构保持与 header 正常处理后相同的状态.
我在让 pre-compiled header 工作时遇到了麻烦,所以我想出了以下 minimal-working-example.
这是 header 文件 foo.h
#include <iostream>
using namespace std;
void hello() {
cout << "Hello World" << endl;
}
我将其编译为 g++ -c foo.h
给我编译的 header foo.gch
。我希望当我编译以下包含 foo.h
的源文件时,它应该选择 header 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
但是,如果我按如下方式更改包含的 header 文件的顺序:
// test.cpp
#include "foo.h" // ------------------
#include <cstdio> // Ordering swapped
int main() {
hello();
}
现在,如果我使用 g++ -H test.cpp
编译,它会从 foo.h.gch
编译,哇!
所以我想知道这是 GCC 中的错误还是我们应该像那样使用 pre-compiled header?无论哪种情况,我都认为了解它很有用..
使用 GCC,预编译的 headers 工作 仅 如果它们是 仅 header,并且如果它们首先包含在内(没有任何先前的 header)。
This answer 更详细地解释了为什么会这样。 另见 GCC 文档的 Precompiled headers 章节,其中说:
- Only one precompiled header can be used in a particular compilation.
- A precompiled header can't be used once the first C token is seen.
顺便说一句,pre-compiling 一些大的 header(特别是在 C++ 中)可能不值得付出努力。 YMMV.
来自 GCC manual pages:
A precompiled header can't be used once the first C token is seen.
因此,在您的预编译 header 中包含 <cstdio>
或首先包含它都可以。
简而言之,预编译的 header 是这样工作的:
当您请求创建“.pch”文件时,编译器会照常处理源文件。在这样做的同时,它的内部结构(主要是名称表和所有相关数据)被填充。最后,它对这些内部结构进行快照并将其保存到“.pch”文件中。
稍后,在编译包含 header 且存在“.pch”文件的源文件时,编译器可以省略 header 文件的昂贵处理并加载 ready-for-use 取而代之的是 '.pch' 文件的快照。
显然,只有在以下情况下才能在不影响语义的情况下完成此操作:
- 包含指令先于其他;
- 编译器选项相同。
包含指令之前的任何内容都可以:
- 向编译器的内部数据结构添加一些内容;
- 影响header文件的处理;
- 改变那里描述的实体之间的关系。
因此,在这种情况下,加载内部数据结构的快照将是错误的,因为无法保证它会使这些结构保持与 header 正常处理后相同的状态.