组织C文件

Kyl*_*nin 28 c file-organization header

我习惯在一个C文件中完成所有编码.但是,我正在开展一个足够大的项目,这样做变得不切实际.我一直在#including他们,但是我遇到了多次#include一些文件的情况,等等.我听说过.h文件,但我不确定他们的功能是什么(或者为什么有2个文件比1)好.

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

这个问题促成了我的询问.tea.h文件没有引用tea.c文件.编译器是否"知道"每个.h文件都有一个相应的.c文件?

csc*_*hol 35

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

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

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

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

例如:

Module1.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;
    }

Module1.h:

    #ifndef __MODULE1.H
    #define __MODULE1.H

    extern unsigned int MyExternVariable;

    void MyExternFunction(void);      

    #endif

Module2.c

    #include "Module.1.h"

    static void MyLocalFunction(void);

    static void MyLocalFunction(void)
    {
      MyExternVariable = 1u;
      MyExternFunction();
    }


And*_*rew 10

尝试使每个.c专注于特定的功能区域.使用相应的.h文件来声明这些函数.

每个.h文件都应该有一个"标题"保护它的内容.例如:

#ifndef ACCOUNTS_H
#define ACCOUNTS_H
....
#endif
Run Code Online (Sandbox Code Playgroud)

这样你可以根据需要多次包含"accounts.h",并且第一次在特定的编译单元中看到它将是唯一真正吸引其内容的人.


den*_*ips 7

一些简单的规则要开始:

  1. 将您想要"公开"的声明放入要创建的C实现文件的头文件中.
  2. 只有#include C文件中实现C文件所需的头文件.
  3. 仅当头文件中的声明需要时,才在头文件中包含头文件.

  4. 如果编译器支持,请使用Andrew描述的include guard方法或使用#pragma(执行相同的操作 - 有时更高效)

  • 这是一个很好的观点.标题(.h)文件应仅包含您要公开的函数.任何私有的编译单元(细节实施细节)都不应该存在; 将它们留在代码(.c)文件中. (2认同)
  • 添加xxx.h文件应该包含在xxx.c中,以确保定义(xxx.c)和声明(xxx.h)一致(不一致会导致非常讨厌的错误)。如果您有供广大公众使用的内容和其他供本地使用的相邻文件,请务必创建 xxx.h 和 xxx-local.h。 (2认同)

Ada*_*vis 7

编译器

您可以在此主题中看到C'模块的示例- 请注意,有两个文件 - 标题tea.h和代码tea.c. 您声明了其他程序要在标头中访问的所有公共定义,变量和函数原型.在您的主项目中,您将#include,并且该代码现在可以访问标题中提到的茶模块的函数和变量.

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

链接

编译两个单独的C文件时,编译器会生成单独的目标文件 - 因此main.c变为main.o,而tea.c变为tea.o. 链接器的工作是查看所有目标文件(你的main.o和tea.o),并匹配引用 - 所以当你在main中调用tea函数时,链接器会修改该调用,所以它实际上调用了右边的在茶中的功能.链接器生成可执行文件.

有一个很好的教程可以更深入地讨论这个主题,包括你将遇到的范围和其他问题.

祝好运!

-亚当