理解问题:预编译标题&包括用法

时间:2015-08-09 15:16:07

标签: c++ include precompiled-headers

我对预编译头文件以及#include指令的用法有一个理解问题。 所以我在这里得到了我的“stdafx.h”并包含了例如vector,iostream和string。关联的“stdafx.cpp”只包含“stdafx.h”,这很清楚。

因此,如果我设计自己的头文件,例如使用vector或iostream中的“代码”,我必须包含头文件,因为编译器当时不知道声明。那么为什么这里的一些帖子(include stdafx.h in header or source file?)说,将“stdafx.h”包含在其他头文件中并不好,即使这个文件包含所需的声明,例如:引导?所以基本上直接包含一个向量或预编译的头文件并不重要,两者都做同样的事情。

我当然知道,如果关联的源文件包含所需的头文件,我不必在另一个头文件中包含头文件,因为声明在那时是已知的。好吧,只有在头文件包含在某处时才有效。

所以我的问题是:我应该避免在任何源文件中包含预编译的头文件,为什么?我有点困惑,因为我正在网上阅读矛盾的表达,我不应该在头文件中包含任何东西,或者是O.K.包含在头文件中? 那现在怎么样?

3 个答案:

答案 0 :(得分:3)

这将是一个有意图的一揽子声明。 Visual Studio项目follows this general design中PCH的典型设置,值得一看。那说:

  1. 将头文件设计为好像没有PCH主标题。
  2. 永远不要在标题中构建包含顺序依赖项,您希望包含源文件在标题之前完成。
  3. 尽管PCH主标头(我稍后会谈到),但始终在源文件中的标准标头之前包含您的自定义标头。这使得您的自定义标头更有可能被正确定义,并且不依赖于包含源文件以前包含的某些标准头文件。
  4. 始终设置适当的包含警卫或编译指示以避免多重包含。它们对于正常工作至关重要。
  5. PCH主标头不包含在头文件中。在设计标题时,请执行此操作,以便包含标题编译所需的所有内容(以及所需的内容)。如果包含源文件需要其实现的附加包含,它可以在标头之后根据需要将它们拉入。

    以下是我如何设置在.h和.cpp文件中使用多个标准标头的项目的示例。

    <强> myobject.h

    #ifndef MYAPP_MYOBJECT_H
    #define MYAPP_MYOBJECT_H
    
    // we're using std::map and std::string here, so..
    #include <map>
    #include <string>
    
    class MyObject
    {
        // some code
    
    private:
        std::map<std::string, unsigned int> mymap;
    };
    
    #endif
    

    注意上面的标题应该包含在它包含的任何.cpp中,使用或不使用PCH 。到源文件......

    <强> myobject.cpp

    // apart from myobject.h, we also need some other standard stuff...
    
    #include "myobject.h"
    #include <iostream>
    #include <fstream>
    #include <algorithm>
    #include <numeric>
    
    // code, etc...
    

    注意myobject.h不希望您包含它所依赖的内容。它未在标题中使用<iostream><algorithm>等;我们在这里使用它。

    这是没有PCH的典型设置。现在我们添加PCH主人

    添加PCH主标题

    那么我们如何设置PCH主站头来对这个东西进行涡轮增压?为了这个答案,我只是处理标准的标题和第三方库标题,这些标题不会随着项目开发而发生变化。您不会编辑<map><iostream>(如果您是,请检查您的头部)。总之...

    1. See this answer了解如何在Visual Studio中配置PCH。它显示了一个文件(通常是stdafx.cpp)如何负责生成PCH,其余的源文件然后通过包含stdafx.h来使用所述PCH。

    2. 决定PCH中的内容。作为一般规则,这就是您应该如何配置PCH。把非易失性的东西放在那里,剩下的用于常规来源包括。我们使用了许多系统标题,这些将成为我们PCH主人的选择。

    3. 确保参与PCH turbo模式的每个源文件都包含PCH主标题 first ,如(1)中的链接答案中所述。

    4. 首先,PCH主标题:

      <强> stdafx.h中

      #ifndef MYAPP_STDAFX_H
      #define MYAPP_STDAFX_H
      
      // MS has other stuff here. keep what is needed
      
      #include <algorithm>
      #include <numeric>
      #include <iostream>
      #include <fstream>
      #include <map>
      #include <string>
      
      #endif
      

      最后,配置为使用它的源文件然后执行此操作。所需的 minimal 更改是:

      更新:myobject.cpp

      #include "stdafx.h" // <=== only addition
      #include "myobject.h"
      #include <iostream>
      #include <fstream>
      #include <algorithm>
      #include <numeric>
      
      // code, etc...
      

      注意我说 minimal 。实际上,这些标准标题都不再出现在.cpp中了,因为PCH主人正在将它们拉进去。换句话说,你可以这样做:

      更新:myobject.cpp

      #include "stdafx.h"
      #include "myobject.h"
      
      // code, etc...
      

      您选择与否取决于您自己。我宁愿保留它们。是的,可以延长源文件的预处理器阶段,因为它会拉入标题,运行到包含警戒器,然后抛弃所有内容直到最终#endif。如果您的平台支持#pragma once(和VS确实),那么它将变为近乎无操作。

      但不要搞错:所有这一切中最重要的部分是标题myobject.h未完全更改 ,并且包含,或者知道,PCH主标题。它不应该,也不应该被构建,所以它必须。

答案 1 :(得分:0)

使用预编译头功能时,每个.cpp文件必须以包含stdafx.h头开头。如果没有,则会产生编译器错误。因此将include包含在某个头文件中是没有意义的。除非首先包含stdafx.h,否则不能包含该头文件。

答案 2 :(得分:0)

预编译头是一种缩短构建时间的方法。这个想法是编译器可以在头文件中“预编译”声明和定义,而不必再次解析它们。

凭借当今计算机的速度,预编译仅对大型项目有意义。这些是至少有超过50,000行代码的项目。 “意义”的定义通常需要几十分钟才能建立。

微软的stdafx.h存在很多问题。根据我的经验,发现和解决问题所花费的精力和时间使得此功能对于较小的项目规模而言更加麻烦。我的构建设置如此大部分时间,我只编译了几个文件;未编译的文件未编译。因此,我没有看到预编译头的任何巨大影响或好处。