对'的建议;C';项目架构指南?

对'的建议;C';项目架构指南?,c,architecture,coding-style,C,Architecture,Coding Style,现在,我已经将注意力集中在“C”语言上,我觉得自己已经足够熟练地编写干净的代码了,我想把注意力集中在项目架构指南上。我正在寻找一个好的资源,包括以下主题: 如何创建一个接口,以提高代码的可维护性,并为将来的升级提供可扩展性 图书馆创建指南。例如,什么时候应该考虑使用静态VS动态库。如何正确地设计一个ABI来处理任何一个 头文件:分区内容和时间。关于何时使用1:1 vs 1:many.h到.c的示例 您觉得我遗漏了但在尝试构建新的C项目时很重要的任何内容 理想情况下,我希望看到一些从小到大的示例项

现在,我已经将注意力集中在“C”语言上,我觉得自己已经足够熟练地编写干净的代码了,我想把注意力集中在项目架构指南上。我正在寻找一个好的资源,包括以下主题:

  • 如何创建一个接口,以提高代码的可维护性,并为将来的升级提供可扩展性
  • 图书馆创建指南。例如,什么时候应该考虑使用静态VS动态库。如何正确地设计一个ABI来处理任何一个
  • 头文件:分区内容和时间。关于何时使用1:1 vs 1:many.h到.c的示例
  • 您觉得我遗漏了但在尝试构建新的C项目时很重要的任何内容 理想情况下,我希望看到一些从小到大的示例项目,并了解架构如何根据项目大小、功能或客户而变化

    对于此类主题,您会推荐哪些资源

  • 将表示代码与逻辑分开。这是非常重要的
  • 静态的,如果它们仅用于您的项目中或少数二进制文件中,那么在多次使用时是动态的(节省了很多空间)
  • 每当代码被多次使用时,将其拆分为一个标题

  • <>这是我能给你的一些小提示。

    < P>每当我认真编写C代码时,我就不得不模仿C++中的特性。值得做的主要工作是:

    • 将每个模块看作一个类。在标头中公开的函数类似于公共方法。仅当函数是模块所需接口的一部分时,才将其放在标题中

    • 避免循环模块依赖关系。模块A和模块B不应相互呼叫。您可以将某些内容重构为模块C以避免这种情况

    • >P>再次,遵循C++模式,如果您有一个模块,可以在不同的数据实例上执行相同的操作,那么在接口中有一个创建和删除函数,它将返回一个指向结构的指针,该结构被传递回其他函数。但是为了封装,在公共接口中返回一个void指针,并转换到模块内部的结构

    • 避免使用模块范围变量——前面描述的模式通常会满足您的需要。但是,如果您确实需要模块范围变量,请将它们分组到存储在单个模块范围变量“m”中的结构下或一致的结构下。然后在您的代码中,每当您看到“m.variable”时,您一眼就会知道它是模块作用域结构之一

    • 为避免标题问题,请将#ifndef MY#u header#H#定义防止双重包含的MY#u header#H声明。模块的头文件.h应仅包含该头文件所需的#includes。c文件可以包含编译模块所需的更多包含,但不要将这些包含添加到模块头文件中。这将避免许多名称空间冲突和包含顺序问题


    命名空间清洁-对于库尤其重要。以某种方式将库的名称作为公共函数的前缀。如果您的库被称为“happyland”,则使用诸如“happyland_init”甚至“hl_init”之类的函数

    这适用于静态的使用。您将编写专门化的函数-通过使用静态函数对其他模块隐藏它们


    对于库来说,可重入性也很重要。不要依赖于未划分的全局状态(如果需要,您可以使用typedef struct令牌来保持此状态)。

    关于系统架构的真理是永恒的,它们跨越语言边界。下面是一个关于C的小建议:

    • 每个模块都隐藏着一个秘密。围绕对客户端隐藏信息的界面构建系统。C唯一的类型安全信息隐藏结构是指向不完整结构的指针。深入学习并经常使用

    • 实现的一个接口是一个很好的经验法则。(接口是.h,实现是.c。)有时您需要提供两个与同一个实现相关的接口:一个隐藏表示,另一个公开表示

    • 您需要命名约定

    戴夫·汉森(Dave Hanson)的模型是如何在C语言中处理这类问题的一个极好的模型。在本书中,您将看到如何设计好的接口和实现,以及如何在一个接口上构建另一个接口以形成一致的库。您还将获得一组优秀的初学者界面,可以在自己的应用程序中使用。对于你这样的人,我不能把这本书推荐得太高。它是C语言中架构良好的系统的原型

    如何创建一个 提高代码的可维护性,并且 可扩展,以便将来升级

    通过尽可能少地公开实现细节。比如说,

    • 使用s
    • 如果需要“private”函数,请将其声明为static,不要将其放在.h文件中

    好的列表。关于标题的另一件事是确保每个标题都是自包含的——它包含它需要的任何标题,因此您可以包含它,而不必担心您还需要什么。Re:public接口中的void指针——我更喜欢使用类型定义的不透明结构。这样,您就不必费劲地进行重播,而且它提供了同样的实现保护。同意Matt B.不要返回void*,使用nice typedef'd抽象数据类型。请参阅我在“用您喜爱的语言实现类”问题中的示例:+1了解CII。非常好的书,在很多方面。