
Organization of C files我习惯于在一个C文件中进行所有编码。 但是,我正在做一个足够大的项目,以至于这样做变得不切实际。 我一直将它们一起包含在其中,但是我遇到过多次包含一些文件的情况,等等。我听说过.h文件,但是我不确定它们的功能是什么(或者为什么) 具有2个文件比1个更好。 我应该使用什么策略来组织代码? 是否可以将特定文件的"公用"功能与"专用"功能分开? 这个问题引起了我的询问。 tea.h文件未引用tea.c文件。 编译器是否"知道"每个.h文件都有一个对应的.c文件? 您应该将.h文件视为.c文件的接口文件。每个.c文件代表一个具有一定功能的模块。如果.c文件中的函数被其他模块(即其他.c文件)使用,请将函数原型放入.h接口文件中。通过将接口文件包含在原始模块.c文件以及需要该功能的所有其他.c文件中,您可以将该功能提供给其他模块。 如果只需要某个.c文件中的功能(而无需任何其他模块中的功能),则将其作用域声明为静态。这意味着只能在定义它的c文件中调用它。 跨多个模块使用的变量也是如此。它们应该放在头文件中,并且必须在其中标记关键字" extern"。注意:对于功能,关键字" extern"是可选的。函数始终被视为"外部"。 头文件中的包含防护有助于避免多次包含同一头文件。 例如: Module1.c:
Module1.h:
Module2.c
尝试使每个.c专注于功能的特定领域。使用相应的.h文件来声明这些功能。 每个.h文件的内容都应有一个"标题"保护。例如:
这样,您可以根据需要多次包含" accounts.h",并且第一次在特定的编译单元中看到它是唯一真正吸收其内容的对象。 编译器 您可以在该主题上看到一个C'模块'的示例-注意,有两个文件-头tea.h和代码tea.c。您在头文件中声明希望其他程序访问的所有公共定义,变量和函数原型。在您的主项目中,您将#include并且该代码现在可以访问标头中提到的tea模块的函数和变量。 之后,它变得更加复杂。如果您使用的是Visual Studio和许多其他的IDE为您管理构建,请忽略此部分-它们负责编译和链接对象。 连接器 当您编译两个单独的C文件时,编译器会生成单独的目标文件-因此main.c成为main.o,tea.c成为tea.o。链接器的工作是查看所有目标文件(您的main.o和tea.o),并匹配引用-因此,当您在main中调用tea函数时,链接器会修改该调用,因此实际上会调用正确的在茶中起作用。链接器生成可执行文件。 有一个很棒的教程可以深入探讨该主题,包括范围和您将遇到的其他问题。 祝好运! -亚当 要开始的几个简单规则: 除了上面提供的答案外,将代码扩展为模块(单独的文件)的一个小好处是,如果您必须具有任何全局变量,则可以通过使用关键字'将它们的范围限制为单个模块。静态的'。 (您也可以将其应用于函数)。请注意,"静态"的这种用法与其在函数内部的用法不同。 要回答您的其他问题:
编译器主要不关心头文件。编译器的每次调用都会将源(.c)文件编译为目标(.o)文件。在幕后(即
源文件 (我在这里详细介绍了一些细节。有关构建C项目的知识很多。) 您的问题清楚地表明,您并没有真正认真地进行过开发。通常的情况是您的代码通常太大而无法放入一个文件中。一个好的规则是,您应该将功能拆分为逻辑单元(.c文件),并且每个文件中所包含的内容不得超过一次即可轻松保存的内容。 然后,给定的软件产品通常包括许多不同的.c文件的输出。通常,编译器会生成许多目标文件(在unix系统中的" .o"文件中,VC会生成.obj文件)。"链接器"的目的是将这些目标文件组合到输出中(共享库或可执行文件)。 通常,您的实现(.c)文件包含实际的可执行代码,而头文件(.h)在这些实现文件中具有公共功能的声明。您可以轻松拥有比实现文件更多的头文件,并且有时头文件也可以包含内联代码。 实现文件相互包含通常是非常不寻常的。优良作法是确保每个实现文件将其关注点与其他文件分开。 我建议您下载并查看linux内核的源代码。对于C程序而言,这是非常庞大的,但是可以很好地组织到单独的功能区域中。 .h文件应用于定义函数的原型。这是必需的,因此您可以在C文件中包含所需的原型,而无需在一个文件中声明所有需要的功能。
例如,当您 如果您只编写功能不多的琐碎应用程序,则实际上没有必要将所有内容模块化成逻辑的过程组。但是,如果需要开发大型系统,则需要考虑在何处定义每个函数。 |