对“C”项目架构指南的建议?

时间:2010-05-08 00:25:42

标签: c architecture coding-style

既然我已经把我的脑袋缠绕在'C'语言上,以至于我已经足够熟练地编写干净的代码了,我想把注意力集中在项目架构指南上。我正在寻找一个包含以下主题的好资源:

  1. 如何创建一个促进代码可维护性的界面,并且可以扩展以供将来升级。
  2. 图书馆制作指南。例如,我应该何时考虑使用静态库和动态库。如何正确设计ABI以应对任何一个。
  3. 标题文件:分区的内容和时间。何时使用1:1 vs 1:许多.h到.c
  4. 的示例
  5. 你觉得我错过了什么但是在尝试构建一个新的C项目时很重要。
  6. 理想情况下,我希望看到一些示例项目,从小到大,看看架构如何根据项目规模,功能或客户而变化。

    您会为这些主题推荐哪些资源?

5 个答案:

答案 0 :(得分:11)

每当我认真编写C代码时,我都必须在其中模拟C ++功能。值得做的主要是:

  • 将每个模块视为一个类。您在标题中公开的函数就像公共方法。如果它是模块所需接口的一部分,则只在头部放置一个函数。

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

  • 再次,遵循C ++模式,如果你有一个模块可以对不同的数据实例执行相同的操作,你的接口中有一个create和delete函数,它将返回一个指向struct的指针,该指针将被传回到其他功能。但是为了封装,在公共接口中返回一个void指针并转换到模块内部的struct。

  • 避免使用模块范围变量 - 之前描述的模式通常可以满足您的需求。但是,如果您确实需要模块范围变量,请将它们分组存储在一个存储在名为“m”的单个模块范围变量中的结构中,或者保持一致。然后在你的代码中看到“m.variable”时,你会一眼就知道它是模块范围结构之一。

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

答案 1 :(得分:8)

关于架构系统的真理是永恒的,它们跨越了语言界限。以下是关于C的一点建议:

  • 每个模块都隐藏了一个秘密。围绕接口围绕隐藏信息构建您的系统。 C唯一的类型安全信息隐藏构造是指向不完整结构的指针。彻底学习并经常使用它。

  • 实现的一个接口是一个很好的经验法则。 (接口是.h,实现是.c。)有时你会想要提供与同一个实现相关的两个接口:一个隐藏表示,一个暴露它。

    < / LI>
  • 您需要命名约定。

如何处理C中的这类问题的一个极好的模型是Dave Hanson的C Interfaces and Implementations。在其中,您将了解如何设计良好的接口和实现,以及一个接口如何构建另一个接口以形成一个连贯的库。您还将获得一组优秀的入门接口,您可以在自己的应用程序中使用它们。对于你所在职位的人来说,我不能过高推荐这本书。这是C语言中架构良好的系统的原型。

答案 2 :(得分:4)

命名空间清洁度 - 对于库来说尤其重要。以某种方式使用库的名称为您的公共函数添加前缀。如果您的图书馆被称为“happyland”,请创建诸如“happyland_init”甚至“hl_init”之类的函数。

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

对于图书馆来说,重入也很重要。不依赖于未划分的全局状态(如果需要,可以使用typedef结构标记来保持此状态。)

答案 3 :(得分:3)

  1. 将演示代码与逻辑分开。这非常很重要。
  2. 静态如果它们仅在您的项目或少数二进制文件中使用,动态多次使用(节省很多空间)。
  3. 每当代码被多次使用时,将其拆分为标题。
  4. 这些是我可以给你的一些已知技巧。

答案 4 :(得分:3)

  

如何创建一个接口   促进代码可维护性并且是   可扩展以供将来升级。

尽可能少地公开实现细节。例如,

  • 使用opaque pointer s。
  • 如果您需要“私人”功能,请将其声明为static,并且不要将其放在.h文件中。