【问题标题】:Header per source file每个源文件的标头
【发布时间】:2009-07-22 20:02:16
【问题描述】:

我试图了解每个源文件方法都有一个标头背后的目的。正如我所看到的,标头用于在使用它们的几个文件之间共享函数声明、typedef 和宏。当您为 .c 文件创建头文件时,它的缺点是每次您想要查看函数声明或宏时都需要引用头文件,而且通常更简单的是所有内容都在一个源文件中(当然,不是整个软件)。

那么程序员为什么要使用这种方法呢?

【问题讨论】:

    标签: c header


    【解决方案1】:

    C 中的头文件将声明(必须对使用函数的每个 .c 文件都可用)与定义(必须在一个位置)分开。此外,它们提供了一点模块化,因为您只能将公共接口放入头文件中,而不提及应该在 .c 文件内部的函数和静态变量。它使用文件系统来提供公共接口和私有实现。

    一个.h 文件到一个.c 文件的做法主要是为了方便。这样,您就知道声明在 .h 文件中,而定义在相应的 .c 文件中。

    【讨论】:

    • 如果我有需要由多个文件共享的声明,并且它们在逻辑上不对应一个 .c 文件?比如说,大多数文件都使用了一些#define。用所有这些创建一个头文件不是更好吗?与一个 .c 文件无关的中性东西?
    • 是的。这个想法是每个标题都包含一组相互关联的声明。在大多数情况下,每个 .c 文件都有一个对应的 .h 是合适的,但您可以添加额外的 .h 文件(例如,定义全局常量或枚举)。最终,您将负责如何使用标头来组织代码。
    • @JasonWilliams:或者额外的 .c 文件,只要合适。
    • @Deduplicator:是的(OP 专门询问标头,因此特别关注 .h)
    【解决方案2】:

    逻辑、结构化的组织和小源文件支持:

    • 更快、更好的编程 - 将代码分成更易于管理和易于理解的块,以便更轻松地查找、理解和编辑相关代码。
    • 代码可重用性 - 不同的代码“模块”可以分成源/头文件组,您可以更轻松地将它们集成到不同的程序中。
    • 更好的“封装” - 只有明确包含该标头的 .c 文件才能使用其中的功能,这有助于您最大限度地减少代码不同部分之间的关​​系,从而有助于模块化。它不会阻止你在任何地方使用东西,但它可以帮助你思考为什么特定的 c 文件需要访问在特定头文件中声明的函数。
    • 有助于团队合作 - 两个程序员试图同时更改同一个代码文件通常会导致问题(例如排他锁)或额外工作(例如代码合并),从而使彼此速度变慢。
    • 更快的编译 - 如果你有一个标题,那么每次你对它进行更改时,你都必须重新编译所有内容。有很多小头文件,只有#include改变头文件的.c文件必须重建。
    • 更易于维护和重构 - 出于以上所有原因

    特别是,“每个源文件一个头文件”可以很容易地找到与您正在使用的 c 文件相关的声明。一旦您开始将多个头文件合并到一个文件中,它就开始变成很难关联 c 和 h 文件,最终使构建大型应用程序变得更加困难。如果您只是在处理小型应用程序,那么养成使用可扩展方法的习惯仍然是一个好主意。

    【讨论】:

      【解决方案3】:

      程序员使用这种方法是因为它允许他们将接口与实现分开,同时保证客户端代码和实现就函数的声明达成一致。 .h 文件是关于每个函数原型的“单一事实”(请参阅​​不要重复自己)。

      (客户端代码是#include的.h文件为了使用导出的函数而编写的代码,但没有实现.h中的任何函数。)

      【讨论】:

        【解决方案4】:

        因为,正如您自己所说,将“整个软件”放在一个源文件中是不可行的。

        如果您的程序非常小,那么将所有内容放在一个 .c 文件中会更简单。随着程序变得越来越大,通过将相关函数放在不同的 .c 文件中来组织事物变得很有帮助。此外,在 .h 文件中,您可以将您给出的声明限制为应该被其他 .c 文件中的事物使用的事物的声明。如果 .c 文件不包含任何可在其外部访问的内容,则它不需要标头。

        例如,如果 .c 有函数 foo() 和 fooHelper(),但是除了 foo() 之外没有人应该直接调用 fooHelper(),那么通过将 foo() 和 fooHelper() 放入 foo.c,只有将 foo() 的声明放在 foo.h 中,并将 fooHelper() 声明为静态,这有助于强制程序的其他部分只能访问 foo(),而不应该知道或关心 fooHelper()。一种非面向对象的封装形式。

        最后,make 引擎通常足够聪明,可以仅重新构建自上次构建以来已更改的文件,因此拆分为多个 .c 文件(使用 .h 文件来共享需要共享的内容)有助于加快构建速度。

        【讨论】:

          【解决方案5】:

          您只需在头文件中放入其他源文件需要“查看”才能进行编译的最低限度的内容。我见过一些人将所有非代码都放入头文件(所有 typedef、所有#define、所有结构等),即使代码库中没有其他内容会使用它们。这使得你自己和想要使用你的模块的人更难阅读头文件。

          【讨论】:

            【解决方案6】:

            每个源文件不需要一个标题。每个模块一个标头,包含公共接口,可能还有一个包含私有声明等的附加标头,该标头在该模块中的文件之间共享。

            【讨论】:

              【解决方案7】:

              通常,源文件方法的标头意味着您仅在该标头中声明来自该编译单元的函数。

              这样你就不会被你不需要的声明所污染。 (在大型软件项目中可能会出现问题)

              对于单独的编译单元,如果将私有符号声明为静态,它们可以加快编译速度并帮助您避免冲突。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2012-04-14
                • 2012-08-09
                • 1970-01-01
                • 2018-07-11
                • 1970-01-01
                • 2010-09-06
                • 1970-01-01
                • 2018-06-24
                相关资源
                最近更新 更多