使用 header 个 header 代替重复

Using a header of headers instead of repeating

有什么理由不写一个 header 文件 #include 所有其他 header 文件,而只在每个 c 文件中 #include 那一个 header 文件?

每个 header 文件都已设置 #ifndef ... #define ... #endif

澄清重复;我问的是用户编写的代码而不是系统 headers,其他可能的重复代码没有说明为什么这不是一个好主意的答案。

感谢您的回答,其中一些我没有仔细考虑。我将考虑采用一些较小的 headers 的混合方法来构建适合的模块。 这是我接管的代码库,它是一个我正在慢慢尝试理清的网络。

您的建议是可行的:许多项目都使用此约定。

一些优点:

  • 文件标题的简单性
  • Makefile 中的依赖项更简单,不需要复杂的自动生成的依赖项列表
  • 名称冲突的早期检测。
  • 没有递归包含难题
  • 由于包含顺序不同,没有细微的错误
  • 如果使用预编译 headers,编译速度更快。

一些缺点:

  • header 文件中的任何修改都将导致重新编译项目中的所有源文件。
  • 鼓励缺乏适当的封装
  • 单个文件的编译时间较慢(如果它成为性能问题,请使用预编译 headers 修复此问题)

我们首先将头文件和实现文件拆分为单独文件的原因(除了代码可读性之外)是为了让编译器能够进行增量构建。也就是说,如果我们在 HeadearA.h 中进行只有 ImplA.cImplB.c 需要的更改,则无需重新编译 ImplC.cImplZ.c。但是,如果您按自己的方式进行,编译器将无法知道这一点,并且您最终会为每次重建重新编译所有 .c 文件,无论是否必要。对于构建时间短的小型项目,这没问题。对于构建时间接近 30 分钟的大型项目,这变得令人望而却步。

对于 non-trivial 项目,经常使用两种策略的组合:一个 header 包括常用系统 header,例如 stdbool.hstdint.hstdatomic.h 等。由于这些永远不会改变,因此它们与重建相关。

您还可以包含 project-settings 模块所需的一些 project-settings,因此您在编写新模块时不必关心它们(或在重构它们时更改每个模块) .

然后你有特定的 header 代表你的 module-dependency 树。这些是根据需要包括的。这不仅加快了构建(而不是编译)项目的速度,而且 doc-tools 也可以像 doxygen 一样使用它来自动创建文档的依赖关系树,因此您不必跟踪每个更改手动。 IDE 可以使用类似的方法快速访问相关的 headers/modules.

一个特别适用于 C 的缺点称为命名空间污染。由于 C 不允许自定义命名空间,每个包含的 header 都会将其符号添加到当前编译单元的命名空间中。对于宏,这可能更糟,因为它们是普通的 text-replacements,对上下文的了解非常有限(为此,还要检查 inline 与 function-macro).

主要问题是你最终得到一大碗意大利面条代码,并且一切都知道一切......最终。你改变的任何东西都会产生影响,你最终不得不重构 re-modularize.. . 你没有一点点提醒实际上包括一些 header 来做出 x 应该知道 y 的决定。

但是除了符号可见性和宏扩展的正常问题之外,它没有任何本质上的错误,这应该是边缘情况..