C文件的组织

C文件的组织,c,header,file-organization,C,Header,File Organization,我习惯于在一个C文件中编写所有代码。然而,我正在做一个足够大的项目,这样做是不切实际的。我曾经把它们放在一起,但我遇到过多次把一些文件放在一起的情况,等等。我听说过.h文件,但我不确定它们的功能是什么(或者为什么有2个文件比1个好) 我应该使用什么策略来组织代码?是否可以将特定文件的“公共”函数与“私有”函数分开 这个问题促使我进行调查。tea.h文件没有引用tea.c文件。编译器是否“知道”每个.h文件都有一个对应的.c文件?试着让每个.c集中在特定的功能领域。使用相应的.h文件来声明这些函数

我习惯于在一个C文件中编写所有代码。然而,我正在做一个足够大的项目,这样做是不切实际的。我曾经把它们放在一起,但我遇到过多次把一些文件放在一起的情况,等等。我听说过.h文件,但我不确定它们的功能是什么(或者为什么有2个文件比1个好)

我应该使用什么策略来组织代码?是否可以将特定文件的“公共”函数与“私有”函数分开


这个问题促使我进行调查。tea.h文件没有引用tea.c文件。编译器是否“知道”每个.h文件都有一个对应的.c文件?

试着让每个.c集中在特定的功能领域。使用相应的.h文件来声明这些函数

每个.h文件的内容周围都应该有一个“头”保护。例如:

#ifndef ACCOUNTS_H
#define ACCOUNTS_H
....
#endif

通过这种方式,您可以根据需要多次包含“accounts.h”,并且第一次在特定的编译单元中看到它时,将是唯一一个真正提取其内容的编译单元。

首先有几个简单的规则:

  • 将要“公开”的声明放入正在创建的C实现文件的头文件中
  • 仅在C文件中包含实现C文件所需的头文件
  • 仅当头文件中的声明需要时,才在头文件中包含头文件。
  • 使用Andrew描述的include-guard方法,或者在编译器支持的情况下使用一次#pragma(这做了同样的事情,有时效率更高)
  • 编译程序 您可以在中看到一个C“模块”示例-注意,有两个文件-头文件tea.h和代码tea.C。您可以在标头中声明希望其他程序访问的所有公共定义、变量和函数原型。在您的主项目中,您将#包括并且该代码现在可以访问标题中提到的tea模块的函数和变量

    在那之后它变得更复杂了。如果您正在使用VisualStudio和许多其他IDE为您管理构建,那么请忽略这一部分-它们负责编译和链接对象

    连接器 当您编译两个单独的C文件时,编译器会生成单独的对象文件——因此main.C变成main.o,tea.C变成tea.o。链接器的工作是查看所有对象文件(main.o和tea.o),并匹配引用-因此,当您在main中调用tea函数时,链接器会修改该调用,以便它确实在tea中调用正确的函数。链接器生成可执行文件

    在这个主题上有一个更深入的讨论,包括范围和您将遇到的其他问题

    祝你好运


    -Adam

    你的问题清楚地表明,你实际上没有做太多认真的开发。通常情况下,您的代码通常太大,无法放入一个文件中。一个很好的规则是,您应该将功能划分为逻辑单元(.c文件),每个文件中包含的内容不应超过您一次可以轻松保存在头脑中的内容

    一个给定的软件产品通常包括许多不同的.c文件的输出。通常情况下,编译器会生成许多对象文件(在unix系统中为“.o”文件,VC生成.obj文件)。“链接器”的目的是将这些对象文件组成输出(共享库或可执行文件)

    通常,实现(.c)文件包含实际的可执行代码,而头文件(.h)在这些实现文件中包含公共函数的声明。您可以很容易地拥有比实现文件更多的头文件,有时头文件也可以包含内联代码

    实现文件之间相互包含通常是很不寻常的。一个好的实践是确保每个实现文件将其关注点与其他文件分开


    我建议您下载并查看linux内核的源代码。对于C程序来说,它是相当庞大的,但是可以很好地组织成不同的功能区域。

    您应该将.h文件视为.C文件的接口文件。每个.c文件代表一个具有一定功能的模块。如果.c文件中的函数被其他模块(即其他.c文件)使用,则将函数原型放入.h接口文件中。通过将接口文件包括在原始modules.c文件中以及需要函数的其他每个.c文件中,可以将此函数提供给其他模块

    如果您只需要某个.c文件中的函数(不在任何其他模块中),请将其作用域声明为静态。这意味着只能从定义它的c文件中调用它

    跨多个模块使用的变量也是如此。它们应该放在头文件中,并且必须在那里用关键字“extern”进行标记。注意:对于函数,关键字“extern”是可选的。函数始终被视为“外部函数”

    头文件中的包含保护有助于避免多次包含相同的头文件

    例如:

    #ifndef ACCOUNTS_H
    #define ACCOUNTS_H
    ....
    #endif
    
    模块1.c:

    #include "Module1.h" static void MyLocalFunction(void); static unsigned int MyLocalVariable; unsigned int MyExternVariable; void MyExternFunction(void) { MyLocalVariable = 1u; /* Do something */ MyLocalFunction(); } static void MyLocalFunction(void) { /* Do something */ MyExternVariable = 2u; } #包括“模块1.h” 静态void MyLocalFunction(void); 静态无符号整数MyLocalVariable; 无符号int-myextern变量; void MyExternFunction(void) { MyLocalVariable=1u; /*做点什么*/ MyLocalFunction(); } 静态void MyLocalFunction(void) { /*做点什么*/ MyExternVariable=2u; } 模块1.h:

    #ifndef __MODULE1.H #define __MODULE1.H extern unsigned int MyExternVariable; void MyExternFunction(void); #endif #ifndef uu模1.H #定义uu模1.H extern无符号int-myextern变量; void myextern函数(void); #恩迪夫 模块2.c

    #include "Module.1.h" static void MyLocalFunction(void); static void MyLocalFunction(void) { MyExternVariable = 1u; MyExternFunction(); } #包括“模块1.h” 静态void MyLocalFunction(void); 静态void MyLocalFunction(void) { MyExternVariable=1u; MyExternFunction(); }