每个源文件的标头

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

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

C语言中的头文件单独声明(必须可用于每个使用函数的.c文件)来自定义(必须在一个地方)。 此外,它们提供了一点模块性,因为您只能将公共接口放入头文件中,而不能提及应该在.c文件内部的函数和静态变量。 这使用文件系统来提供公共接口和私有实现。

一个.h文件到一个.c文件的做法大多是方便的。 这样,您就知道声明在.h文件中,以及相应的.c文件中的定义。

逻辑,结构化组织和小型源文件支持:

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

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

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

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

例如,如果.c有函数foo()和fooHelper(),但是除了foo()之外的任何人都不应该直接调用fooHelper(),那么将foo()和fooHelper()放到foo.c中,只需要声明在foo.h中的foo(),并将fooHelper()声明为静态,它有助于强制程序的其他部分只应访问foo()并且不应该知道或关心fooHelper()。 一种非面向对象的封装forms。

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

您只需将头文件放入其他源文件需要“查看”以便编译的最低限度。 我已经看到一些人将所有非代码放入头文件(所有typedef,所有#define,所有结构等),即使代码库中没有其他东西会使用它们。 这使得头文件更难以为自己和那些想要使用您的模块的人阅读。

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

(客户端代码是#include的.h文件的代码,以便使用导出的函数,但不实现.h中的任何函数。)

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

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

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

对于单独的编译单元,这些可以加速编译,并且可以帮助您避免在私有符号被声明为静态时发生冲突。