【发布时间】:2009-07-22 20:02:16
【问题描述】:
我试图了解每个源文件方法都有一个标头背后的目的。正如我所看到的,标头用于在使用它们的几个文件之间共享函数声明、typedef 和宏。当您为 .c 文件创建头文件时,它的缺点是每次您想要查看函数声明或宏时都需要引用头文件,而且通常更简单的是所有内容都在一个源文件中(当然,不是整个软件)。
那么程序员为什么要使用这种方法呢?
【问题讨论】:
我试图了解每个源文件方法都有一个标头背后的目的。正如我所看到的,标头用于在使用它们的几个文件之间共享函数声明、typedef 和宏。当您为 .c 文件创建头文件时,它的缺点是每次您想要查看函数声明或宏时都需要引用头文件,而且通常更简单的是所有内容都在一个源文件中(当然,不是整个软件)。
那么程序员为什么要使用这种方法呢?
【问题讨论】:
C 中的头文件将声明(必须对使用函数的每个 .c 文件都可用)与定义(必须在一个位置)分开。此外,它们提供了一点模块化,因为您只能将公共接口放入头文件中,而不提及应该在 .c 文件内部的函数和静态变量。它使用文件系统来提供公共接口和私有实现。
一个.h 文件到一个.c 文件的做法主要是为了方便。这样,您就知道声明在 .h 文件中,而定义在相应的 .c 文件中。
【讨论】:
逻辑、结构化的组织和小源文件支持:
特别是,“每个源文件一个头文件”可以很容易地找到与您正在使用的 c 文件相关的声明。一旦您开始将多个头文件合并到一个文件中,它就开始变成很难关联 c 和 h 文件,最终使构建大型应用程序变得更加困难。如果您只是在处理小型应用程序,那么养成使用可扩展方法的习惯仍然是一个好主意。
【讨论】:
程序员使用这种方法是因为它允许他们将接口与实现分开,同时保证客户端代码和实现就函数的声明达成一致。 .h 文件是关于每个函数原型的“单一事实”(请参阅不要重复自己)。
(客户端代码是#include的.h文件为了使用导出的函数而编写的代码,但没有实现.h中的任何函数。)
【讨论】:
因为,正如您自己所说,将“整个软件”放在一个源文件中是不可行的。
如果您的程序非常小,那么将所有内容放在一个 .c 文件中会更简单。随着程序变得越来越大,通过将相关函数放在不同的 .c 文件中来组织事物变得很有帮助。此外,在 .h 文件中,您可以将您给出的声明限制为应该被其他 .c 文件中的事物使用的事物的声明。如果 .c 文件不包含任何可在其外部访问的内容,则它不需要标头。
例如,如果 .c 有函数 foo() 和 fooHelper(),但是除了 foo() 之外没有人应该直接调用 fooHelper(),那么通过将 foo() 和 fooHelper() 放入 foo.c,只有将 foo() 的声明放在 foo.h 中,并将 fooHelper() 声明为静态,这有助于强制程序的其他部分只能访问 foo(),而不应该知道或关心 fooHelper()。一种非面向对象的封装形式。
最后,make 引擎通常足够聪明,可以仅重新构建自上次构建以来已更改的文件,因此拆分为多个 .c 文件(使用 .h 文件来共享需要共享的内容)有助于加快构建速度。
【讨论】:
您只需在头文件中放入其他源文件需要“查看”才能进行编译的最低限度的内容。我见过一些人将所有非代码都放入头文件(所有 typedef、所有#define、所有结构等),即使代码库中没有其他内容会使用它们。这使得你自己和想要使用你的模块的人更难阅读头文件。
【讨论】:
每个源文件不需要一个标题。每个模块一个标头,包含公共接口,可能还有一个包含私有声明等的附加标头,该标头在该模块中的文件之间共享。
【讨论】:
通常,源文件方法的标头意味着您仅在该标头中声明来自该编译单元的函数。
这样你就不会被你不需要的声明所污染。 (在大型软件项目中可能会出现问题)
对于单独的编译单元,如果将私有符号声明为静态,它们可以加快编译速度并帮助您避免冲突。
【讨论】: