c++ - C/C++ - 预编译 header - 封装、如何以及为什么需要配置?

标签 c++ c visual-studio visual-c++ precompiled-headers

我理解预编译头文件可以加快构建时间的想法,但是到目前为止有一些问题阻止我去摸索它们。

  1. 为什么使用预编译 header 需要开发人员进行任何配置?

    为什么编译器(或链接器/IDE?)不能像处理源文件(即 .obj 文件)那样只拥有单独的预编译头目标文件?依赖关系由哪些源/头文件包含哪些其他文件来指示,并且它已经可以检测到源文件何时更改,因此常规构建通常不是完全重建。与其要求我指定预编译哪些 header 等,为什么这一切不总是自动开启,并且对开发人员透明?

  2. 据我了解 Visual Studio 中的预编译 header 方法,想法是您获得一个大 header 文件 (stdafx.h),其中包含您想要预编译的所有其他 header 文件,然后您将其包含在使用任何这些 header 的所有源文件中。

    一个。我理解正确吗?

    这不会破坏封装吗?通常会有效地包括各种(可能)不相关的项目,但您不会这样做,这使得您更难判断您实际使用的是哪些库,以及什么来自哪里。

    在我看来,这种实现会强制实现不良做法。我错过了什么?

  3. 如何在 Visual Studio (2013) 中使用预编译 header ?

  4. 是否有跨平台的方式来使用或促进预编译 header ?

谢谢。

最佳答案

Why can't the compiler (or linker/IDE?) just have individual precompiled header object files, in the same way it does for the source files (i.e. .obj files)?

问题 1 和 2 的答案在于预编译 header 的工作方式。假设您有一个 my_source_file.c:

#include "header1.h"
#include "header2.h"

int func(int x) { return x+1; }

my_other_source_file.c:

#include "header1.h"

int func2(int x) { return x-1; } 

当您调用 compiler.exe my_source_file.c 时,编译器开始解析您的文件。编译器的所有内部变量(例如定义了哪些类型、声明了哪些变量等)都称为编译器状态。

在解析完 header1.h 之后,它可以将状态保存到磁盘。然后,在编译 my_other_source_file.c 时,不需要再次解析 header1.h,它可以加载状态并继续。

该状态是一个预编译头文件。从字面上看,它只是在解析整个 header 后立即转储所有编译器变量。

现在的问题是,为什么不能有两个状态转储,分别用于 header1.hheader2.h 并加载它们。国家不是独立的。第二个文件是 header1.h + header2.h 的状态。所以,通常要做的是在所有公共(public)头文件都已编译并使用它之后,你有一个状态。

理论上,您可以为每种组合使用一个并使用适当的组合,但这比它的值(value)要麻烦得多。

有些事情是这样做的副作用:

  • 不同的编译器(甚至包括次要版本)具有不同的变量,因此您不能重复使用预编译。

  • 由于转储状态从文件顶部开始,因此您的预编译必须是第一个包含。在包含预编译之前,不能有任何可能影响状态的东西(即不是#defines、typedef、声明)。

  • 命令行 (-DMY_DEFINE=0) 传递的任何定义都不会在预编译头文件中被选取。

  • 预编译时命令行传递的任何定义都将对使用预编译的所有源文件生效。

对于 3),请参阅 MSFT documentation .

对于4),大多数编译器都支持预编译头文件,它们的工作方式大致相同。您可以将您的 makefiles/build 脚本配置为始终预编译某个 header (例如 stdafx.h),该 header 将包含所有其他 header 。就您的源代码而言,无论平台如何,您总是#include "stdafx.h"

关于c++ - C/C++ - 预编译 header - 封装、如何以及为什么需要配置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30225208/

相关文章:

c++ - 如何在 C++ 中打开多个单独的终端窗口?

c++ - 无法将 namespace_something::some_class 转换为 some_class

c - Linux C-keyMapping keyCodes

c - 击键生成

c# - 我怎样才能得到按钮的命令参数?

regex - 如何使用正则表达式在 VS Code 的每行末尾添加一个字符串?

c++ - 如何使用结构构造函数初始化结构内部的指针数组?

c++ - 错误 LNK2001 : unresolved external symbol Visual C++

c - 初始化结构数组的全局数组

c# - 在 Visual Studio 中使用 DTE 的程序包管理器控制台自动化