代码之家  ›  专栏  ›  技术社区  ›  Ferruccio

有没有一种方法可以在不需要stdafx.h的情况下在VC++中使用预编译的头文件?

  •  10
  • Ferruccio  · 技术社区  · 16 年前

    我有一堆遗留代码需要为它们编写单元测试。它在任何地方都使用预编译的头文件,因此几乎所有的.cpp文件都依赖于stdafx.h,这使得很难打破依赖项来编写测试。

    我的第一反应是删除所有这些stdafx.h文件,其中大部分包含include指令,并根据需要将这些直接包含在源文件中。

    这就需要关闭预编译头,因为它们依赖于具有类似stdafx.h的文件来确定预编译头的停止位置。

    有没有一种方法可以在不依赖stdafx.h的情况下保留预编译的头文件?有没有更好的方法来解决这个问题?

    9 回复  |  直到 7 年前
        1
  •  9
  •   Len Holgate    14 年前

    是的,有更好的方法。

    imho,预编译头的“向导式”的问题是,它们鼓励不需要的耦合,并使重用代码比它应该的更困难。此外,使用“just stick everything in stdafx.h”样式编写的代码很容易维护起来很困难,因为更改任何头文件中的任何内容都可能导致每次重新编译整个代码库。这可以使简单的重构永远花费时间,因为每次更改和重新编译周期比它应该花费的时间要长得多。

    还有一个更好的方法,imho,就是使用pragma hdrstop和/yc和/yu。这使您能够轻松地设置使用预编译头的生成配置以及不使用预编译头的生成配置。使用预编译头的文件与源文件中的预编译头本身没有直接依赖关系,因此可以使用预编译头或不使用预编译头进行生成。项目文件确定构建预编译头文件的源文件,每个源文件中的pragma hdrstop行确定从预编译头(如果使用)获取哪些内容,以及直接从源文件获取哪些内容…这意味着在进行维护时,您将使用不使用预编译头的配置,并且只有在头文件更改后需要重新生成的代码才会重新生成。在进行完全编译时,可以使用预编译头配置来加快编译过程。使用非预编译头构建选项的另一个好处是,它确保cpp文件只包含它们需要的内容,并包含它们需要的所有内容(如果使用预编译头的“向导样式”,则很难做到这一点)。

    我已经写了一些关于这是如何工作的: http://www.lenholgate.com/blog/2004/07/fi-stlport-precompiled-headers-warning-level-4-and-pragma-hdrstop.html (忽略关于/fi的内容),我有一些示例项目,它们使用pragma hdrstop和/yc/yu方法构建: http://www.lenholgate.com/blog/2008/04/practical-testing-16---fixing-a-timeout-bug.html .

    当然,从“向导样式”的预编译头使用到更受控制的样式通常是非常重要的…

        2
  •  4
  •   jyoung    16 年前

    通常使用预编译头时,“stdafx.h”有两个用途。它定义了一组稳定的、通用的包含文件。同样,在每个.cpp文件中,它作为预编译头的结束位置的标记。

    听起来你想做的是:

    • 保持预编译头处于打开状态。
    • 将“stdafx.h”包含在每个.cpp文件中。
    • 从“stdafx.h”中清空includes。
    • 对于每个.cpp文件,找出旧的“stdafx.h”中需要哪些内容。在每个.cpp文件中的include“stdafx.h”之前添加这些。

    所以现在您有了最小的依赖集,并且仍然在使用预编译头。损失在于您没有只预编译一次常见的头集。这将是一个全面重建的巨大打击。对于开发模式,一次只重新编译几个文件,这样的效果会小一些。

        3
  •  2
  •   Corey Trager    16 年前

    不,可能有 不是 更好的方法。

    但是,对于给定的单个.cpp文件,您可能决定不需要预编译头。您可以修改那个.cpp文件的设置并删除stdafx.h行。

    (实际上,尽管如此,我不知道预编译的报头方案是如何与编写单元测试相冲突的)。

        4
  •  2
  •   user19871    16 年前

    不需要。预编译的头依赖于所有以这种方式编译的源所包含的单个头。 您可以为单个源(或全部)指定根本不使用预编译头,但这不是您想要的。

    过去,Borland C++编译器没有特定的头文件就进行了预编译。但是,如果两个源文件包含相同的头文件,但位于不同的 秩序 它们是分开编译的,因为,C++中头文件的顺序可能很重要。

    因此,这意味着只有当您严格按照相同的顺序包含源文件,或者所有其他文件(首先)包含一个包含文件时,Borland预编译头文件才会节省时间。-听起来很熟悉????!

        5
  •  2
  •   MSalters    16 年前

    对。“stdafx.h/stdafx.pch”名称只是惯例。您可以为每个.cpp提供自己的预编译头。通过一个小脚本来编辑.vcproj中的XML,这可能是最容易实现的。缺点:您最终会得到一个大的预编译头堆栈,它们不会在TU之间共享。

    可能,但聪明?我不能确定。

        6
  •  1
  •   Filip Frącz    16 年前

    我的建议是-不要删除预编译头,除非您想让您的构建非常缓慢。你基本上有三个选择:

    1. 除去预编译头(不推荐)
    2. 为遗留代码创建一个单独的库;这样您就可以单独构建它。
    3. 在单个项目中使用多个预编译头。您可以在解决方案资源管理器中选择单独的C++文件,并告诉它们要使用哪个预编译头。您还需要设置otherstdafx.h/cpp以生成预编译头。
        7
  •  1
  •   Matt Price    16 年前

    预编译的报头是基于这样一个理念:所有内容都将包含相同的一组内容。如果您想使用预编译的头文件,那么您必须使用这意味着的依赖项。归根结底是依赖性与构建速度之间的权衡。如果您可以在合理的时间内构建并关闭预编译头,那么一定要这样做。

    另一个需要考虑的问题是,每个库可以有一个PCH。因此,您可以将代码拆分为较小的库,并使每个库具有更紧密的依赖关系集。

        8
  •  0
  •   graham.reeds    16 年前

    我只对需要包含afx_uuuuuuu内容的代码使用预编译头文件——通常只使用ui,而不进行单元测试。用户界面代码处理用户界面和调用具有单元测试的函数(尽管大多数都不是因为应用程序是遗留的)。

    对于大部分代码,我不使用预编译头。

    G.

        9
  •  0
  •   riderBill    7 年前

    预编译头在重建项目时可以节省大量时间,但是如果预编译头发生更改, 每一个 取决于头的源文件将重新编译,无论更改是否影响它。幸运的是,预编译头用于 编译 不是 链接 ; 每个源文件不必使用 相同的 预编译的头文件。

    PCH1.H:

    #include <bigHeader1.h>
    #include ...
    


    PCH1.CPP:

    #include "pch1.h"
    


    SURCE1.CPP:

    #include "pch1.h"
    [code]
    


    PCH2.H:

    #include <bigHeader2.h>
    #include ...
    


    PCH2.CPP:

    #include "pch2.h"
    


    SureCe2.CPP

    #include "pch2.h"
    [code]
    

    选择 PCH1.CPP ,右击, 属性、配置属性、C/C++、预编译头 .
    预编译头: 创建(/ YC)
    预编译头文件: pH1.H
    预编译头输出文件 :$(intdir)pch1.pch

    选择 SureC1.CPP
    预编译头: 使用(/ YU)
    预编译头文件: pH1.H
    预编译头输出文件 :$(intdir)pch1.pch(我认为这对/yu不重要)

    做同样的事 PCH2.CPP SureCe2.CPP ,除了设置 头文件 头输出文件 PH 2H PCH2.PCH . 这对我很有用。