Visual C++ 预编译头错误

15

更新:

在我的头文件中包含stdafx.h有什么影响?


我开始在Linux/Eclipse CDT上进行C++项目,并将其导入到Visual C++/Windows中。

在Visual C++中,我开始使用预编译头文件来加快编译速度,并定义了stdafx.cpp和stdafx.h。

这是我的stdafx.h:

#pragma once

#include <string>
#include <vector>
#include <map>
...

以及我的stdafx.cpp文件

#include "stdafx.h"

在每个.h和.cpp文件中,我都有以下内容:

#pragma once //if in a header file
#include "stdafx.h"

无论是在发布模式还是调试模式下,我都开启了 "创建预编译头(/Yc)"。它能够在调试模式下成功编译,但在发布模式下会一直报错。

error LNK2005: ___@@_PchSym_@00@UfhvihUaszlaDUwlxfnvmghUnnlUhixUnnlPeDUnnlPeDUivovzhvUvmgrgbOlyq@ already defined in A.obj

如果我把两个都切换成“使用预编译头文件”,那么在Debug和Release模式下都会出现这个问题。

fatal error C1854: cannot overwrite information formed during creation of the precompiled header in object file:

有人知道发生了什么吗?


顺便说一下,我创建了一个新的测试项目,并将其PCH设置与我的进行了比较。它的设置为“使用PCH”。那个项目以某种方式编译成功了。 - jameszhao00
4个回答

30

您需要将“创建预编译头文件”仅应用于stdafx.cpp文件。然后,对于所有其他“.cpp”文件,请使用“使用预编译头文件”。最后,在每个“.cpp”文件的开头添加include "stdafx.h"(通常不在头文件中)。


10
在VS中,您可以右键单击一个文件并选择“属性”。然后在“C++->预编译头”下,您可以将值设置为“create”或“use”。配置范围设置用作默认值-您应该将其设置为“use”,然后覆盖stdafx.cpp。 - 1800 INFORMATION
实际上,头文件本身并不定义可编译单元,因此它们只是其他可编译单元的一部分,所以没有什么影响。 - Aidan Ryan
我知道这是一个老问题,但是我对“通常不在头文件中”的部分感到困惑。你是说为了example.h和example.cpp应该经常包含预编译头文件吗?那么这是否意味着在example.h中包含的文件会被编译两次 - 一次在pch中,一次在example.h中? - Proxy
通常情况下,您不会在头文件中包含stdafx.h。大多数头文件都有某种包含保护,例如指定的“pragma once”,可以防止它们被包含两次而破坏编译。因此,由于它已经在预编译头文件中包含了一次,在其他文件example.h中再次包含它将没有任何效果。 - 1800 INFORMATION
对于那些在stdafx.cpp或任何其他.cpp文件中未能找到“预编译标头”选项的人,请仔细检查该文件的“项目类型”字段是否为“C/C++编译器”。 - dmytro.poliarush
显示剩余2条评论

6
/Yc编译器选项用于为编译动作创建预编译头文件。/Yu选项指示编译器使用预编译头文件。
在项目设置中,您始终会使用/Yu选项。在stdafx.cpp文件的属性页面中,/Yc选项将被设置。
重要的是要理解每个.cpp文件有单独的编译选项。
有关/Y选项的详细信息,请参见此处

4
你把#pragma once放在#include "stdafx.h"之前,我认为这会导致编译器忽略#pragma once指令。
此外,我认为你根本不应该在头文件中放置#include "stdafx.h"行。

2
通常情况下,您会将 #include "stdafx.h" 放在每个 .cpp 文件的第一个 include 中。我认为它实际上必须是第一行非注释行。 - Soo Wei Tan
1
所以基本上我必须在PCH中包含自己的头文件?那么我的头文件中引用的耗时编译的头文件(boost)该怎么办? - jameszhao00
2
例如,如果我在stdafx和my_class.h中都引用了Boost,在my_class.cpp中,因为stdafx已经引用了它,所以会跳过在my_class.h中引用的Boost? - jameszhao00
2
即使头文件必须在其他地方包含,大部分处理也只需作为预编译的一部分进行。您将头文件包含在PCH中以最小化处理,将头文件包含在其他地方以提供类型信息和定义结构。这些包含服务于不同的目的。 - Aidan Ryan
2
虽然这个答案指出了一些问题,但实际上并没有回答链接器错误的问题。 - Aidan Ryan
@Aidan:不,它不是这样工作的。您在stdafx.h中包含的任何标头都可以通过传递包含在任何地方使用。因此,您无需再次包含这些标头。尽管如此,这是无害的,因为Boost标头具有包含保护。 - MSalters

1
使用 "stdafx.h" 的结果不受预编译头系统的影响。如果关闭创建 PCH/使用 PCH,则代码会编译并创建相同的输出,只是速度较慢。这也是为什么您可以在可移植代码中使用它(不像 #pragma once)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接