如何从根目录中包含stdafx.h?

31

在VS中开启“显示所有文件”选项后,我添加了一个文件夹并在其中创建了一个新的类。由于我正在使用预编译头文件,因此还需要相对于新的类文件包含位于根目录下的stdafx.h。

在我的cpp文件中,我有:

#include "..\stdafx.h"

然而我收到了以下错误信息:

错误 C1010: 查找预编译头时遇到意外的文件结尾。你是否忘记在源文件中添加'#include "stdafx.h"'?

我的理解是,'..'应该指示编译器向上一级目录进入?

9个回答

21

Visual C++允许您定义多种设置预编译头文件的方法。最常见的方法是在项目配置级别为所有源文件启用它,在“Configuration Properties/C++/Precompiled Headers”下,将“Precompiled Header”设置为“Use”。在同一位置,将“Precompiled Header File”设置为通常为“stdafx.h”。所有文件都将获取此设置(因此是项目的配置)除了......

有一个文件负责生成PCH文件。该文件通常是项目中的stdafx.cpp文件,并且通常除了#include "stdafx.h"之外没有其他内容。为该文件配置预编译头文件,从“Use”切换到“Create”。这样可以确保如果PCH的主头文件不同步,则始终首先编译stdafx.cpp以重新生成PCH数据文件。在Visual Studio中配置PCH设置的其他方法也存在,但这是最常见的方法。

话虽如此,您遇到的问题肯定很烦人。用于引导PCH系统并在上述“Use...”和“Create...”设置上指定的文件名必须与#include语句中的文本完全匹配

因此,非常有可能您可以通过将“..”添加到项目包含目录中并从#include语句中删除“..”来解决问题。您还可以将其更改为作为整体标头的项目配置级别为“..\stdafx.h”,但如果您在多个文件夹中层次结构地拥有源文件,则可能会出现问题。

哦,如果您在浏览PCH配置设置时不清楚,如果您不想为任何特定源文件使用PCH(有时确实有理由不使用),则可以关闭它,否则请确保始终在每个源文件的头部(c/cpp等) #include "your-pch-include-file.h"。

希望您能摆脱这个问题。


嘿,谢谢你的回答,但我觉得我可能误解了你的意思。在“配置属性”中没有“使用预编译头文件”的设置可用。此外,我已将“..”添加到“配置属性”->“C \ C ++”->“常规”->“附加包含目录”和“配置属性”->“VC ++目录”->“包含目录”。但它们都不起作用。 - Dante
我已更新以反映VS2010配置路径设置。如果您将“..”添加到包含路径中,则还必须从c/cpp文件中的“stdafx.h” #include声明中删除它 - WhozCraig
我从cpp文件中删除了stdafx.h包含的".."部分,该文件在单独的文件夹中。其他所有文件都可以编译,但是单独文件夹中的文件现在会产生错误“error C1083: Cannot open include file: 'stdafx.h': No such file or directory”。 - Dante
1
如果您将所有预编译头文件配置保持默认设置,那么在任何项目子目录中的任何源文件中简单地添加 #include "stdafx.h" 应该可以正常编译。我刚在VS2012上测试过。 - Neutrino

20

一般我也喜欢在我的项目中有一个层次结构,并且我发现有两种简单的方法来包含一个预编译头文件:

要么

  1. 将存放stdafx.h的目录添加到编译器的包含目录中。

    (属性 - VC++目录 - 包含目录: 添加$(ProjectDir))

要么

  1. 如果没有太多的子目录,解决错误信息的一个简单方法如下:

    • 在每个子目录中放置一个stdafx.h文件,该文件仅包括顶级的stdafx.h
      #include "..\stdafx.h"
    • 在所有子目录的源文件的第一行写上#include "stdafx.h",而不是在那里包含顶层文件。

这样,所有的代码文件都使用相同的预编译头文件,而且没有其他复杂的设置要做。


使用MSVC编译器,选项#1和#2都可以工作。使用Intel编译器v19.0,选项#2可以工作(但不是#1)。 - Contango

15

有趣的是,我使用的技巧并没有在答案中:

  1. 在项目的根文件夹中创建stdafx.h和stdafx.cpp。
  2. 转到项目属性->预编译头。更改为"use"。
  3. 进入stdafx.cpp,右键单击属性->预编译头。更改为"create"。
  4. 转到项目属性->高级;将"强制包含文件"更改为stdafx.h;%(ForcedIncludeFiles)

不要更改任何CPP文件; 保持您的头文件不变。按原样构建即可。

无需打字,无需RSI,无需处理包含路径,也没有其他痛苦和烦恼。美妙的是,当您将解决方案移动到另一个平台时,它仍将起作用。棒极了。


4
您可以在每个文件的基础上调整预编译头设置。
  1. 在“解决方案资源管理器”中右键单击 .cpp 文件,选择“属性”。
  2. 我强烈建议在“配置”下拉列表项中选择“所有配置”。
  3. 浏览到“C/C++” - “预编译头”。
  4. 将“预编译头文件”从“stdafx.h”调整为您需要的任何内容(例如: "../stdafx.h")。

请注意,这是繁琐且容易出错的,因为它是基于每个文件的设置,未来添加文件的开发人员将不得不遵循相同的步骤。如果他们没有这样做,他们将面临警告和错误,例如:

  • warning C4627: '#include "<path>"': skipped when looking for precompiled header use.

  • fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?

这些都没有给出更多的指示或其他方法。

我想他们最终会转向StackOverflow并在此结束... 您好,感谢您的阅读。

基于这个基础,使用其他替代方案值得考虑,例如将 $(ProjectDir) 放在 C++ 包含路径(在C++\常规下)中,但这可能会在包含其他头文件时引起混乱。


2
PCH文件很奇怪,尤其是在Visual Studio中。编译使用PCH的.cpp文件时,VS希望第一个非注释/空格文本是#include "PCH_NAME_HERE"PCH_NAME_HERE就是PCH的名称。没有目录,什么都没有。只需按编译器选项中指定的PCH名称即可。
如果要进行此目录操作,则需要修改编译器设置,以便PCH所在的目录位于目录搜索路径中。这样,您就不需要使用..\部分了。

1
我建议使用:

$(ProjectDir)/pch/my_pch.h

作为"预编译头文件"和"高级 > 强制包含文件",这将自动在您的.cpp文件开头包含pch,因此无需更改.cpp文件。这比更改包含目录更好,因为有时您可能会在包含目录中有多个pch文件,然后您无法确定使用了哪个。

0
混淆的原因在于Visual Studio对包含预编译头文件的include指令与其他include指令的处理方式不同。具体来说,它不会使用正常的路径查找方法来寻找预编译头文件,而是通过简单的字符串比较来匹配项目配置中定义的include指令。
预编译头文件配置是全局设置,但可以针对每个文件进行覆盖。正常的全局配置(通过“项目属性”->“配置属性”->“C/C++”->“预编译头”访问)为:
Precompiled Header: Use (/Yu)
Precompiled Header File: stdafx.h
Precompiled Header Output File: $(IntDir)$(TargetName).pch

此配置默认应用于项目中的所有文件。但是,stdafx.cpp 的配置设置在文件级别上,并覆盖了预编译头的值:

Precompiled Header: Create (/Yuc)

这样做的效果是,对于任何配置为使用预编译头文件的源文件(默认情况下除了 stdafx.cpp 之外的所有文件),VS 将查找与配置的预编译头文件值匹配的包含指令。例如:
#include "stdafx.h"

由于检查使用简单的字符串比较而不是任何类型的目录搜索,因此(无论源文件相对于项目根目录的位置或stdafx.h文件的位置如何),在include指令中使用的路径和文件名必须与项目的预编译头文件配置设置完全匹配。这种意外的副作用是,如果您有一个包含各种源文件的项目子目录,在这些文件中,您不需要使用相对路径(如..\stdafx.h)引用stdafx.h文件(如果您这样做,VS将引发错误,指出它在查找预编译头时遇到了文件结尾)。

只需使用未装饰的#include "stdafx.h",它就可以正常工作,因为VS将识别此指令以使用预编译头,并且它已经知道正确的预编译头的位置,因为stdafx.cpp预编译头配置设置为“创建(/Yc)”。


-1

如果您的项目的 .cpp 和 .h 文件位于不同的子目录中(而不是明确在项目目录中),那么使用相对于解决方案目录的包含路径(如果您不使用专用的包含目录)将是一个良好的编码风格。特别是如果您在一个解决方案中有多个项目,并且需要共享包含文件(例如,用于项目之间的互操作性,例如 .exe 和 .dll)。

要重构您的项目,您需要执行以下操作:

  1. 在每个项目中指定附加包含目录 $(SolutionDir):右键单击项目,单击“属性”,转到“配置属性”->“C/C++”->“常规”(要为所有配置同时执行此操作,请从“配置”下拉列表中选择“所有配置”)
  2. 转到“C/C++”->“预编译头”,并将“预编译头文件”值更改为相对于解决方案目录的路径,例如 PROJECT_NAME/stdafx.h
  3. 在您的 .cpp 文件中,包括 "PROJECT_NAME/stdafx.h",而不是仅仅是 "stdafx.h"
  4. 在您的 .h 和 .cpp 文件中,当包含某些内容时,请使用路径 "PROJECT_NAME/dir1/dir2/file.h",除非包含来自同一目录的文件

使用根目录的包含路径是一个非常糟糕的想法。将源代码复制到另一台机器上,甚至重新配置源代码所在的机器都会导致编译失败。此外,如果您使用根目录路径包含stdafx.h文件,Visual Studio仍然会抱怨,因为它不使用标准路径解析算法来定位stdafx.h文件,而是有一些(在我看来是半吊子的)自定义查找机制,实际上这才是问题的根源。 - Neutrino
@ Neutrino,我并不是指像以驱动器号开头的完全根据路径。例如,C:。我已经编辑了答案,使意思更加清晰:我指的是解决方案目录或专用的include目录作为根目录,这样引用包含文件的路径就是相对于这些目录的。在将整个解决方案移动到同一台计算机上的不同目录或计算机之间时,这不会有任何问题。 - Serge Rogatch
@Neutrino,另外,我已经仔细检查了使用解决方案相对路径的建议,例如#include "PROJECT_NAME\stdafx.h",如果按照上述步骤操作,它是有效的。如果您尝试过但没有成功,那么错误是什么? - Serge Rogatch
关于根路径的问题,你的建议是合理的。然而,你提出的调整项目“附加包含目录”配置以便让Visual Studio能够找到子目录中预编译头文件的做法并不必要。请参考我的回答获取更多细节。 - Neutrino

-4

使用引号表示它是你自己的头文件 <> 表示它是一个系统头文件,如果我没有搞错,只需使用 #include <stdafx.h> 让编译器找到它即可


1
“stdafx.h”不是系统文件,而是预编译头文件。 - Nicol Bolas
不是Windows的人,那为什么它有一个.h扩展名? - Adrian Cornish
因为它是一个头文件。它可能是预编译的,但它仍然是一个头文件。 - Nicol Bolas
头文件是一个预编译的文件,这意味着它已经被修改过了。而 .o 文件只是一个预编译的 .c 文件 :-) 为什么扩展名没有改变呢?并不是说扩展名就是文件格式的全部和终极标准。 - Adrian Cornish
实际的预编译文件不是一个.h文件。也就是说,这不是它的名称。当编译器被告知有一个PCH时,它会在看到#include "PCH_NAME_HERE.h"时替换预编译符号,通过将PCH_NAME_HERE.h转换为具有预编译符号的实际文件名。PCH_NAME_HERE.h仍然是技术上的常规头文件;其背后的想法是您可以像没有使用PCH一样编译相同的文件。 - Nicol Bolas

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