2010-05-08 162 views
15

现在,我已经把自己的头围绕在“C”语言之上,以致于我觉得足够精通以编写干净的代码,所以我想将注意力集中在项目架构指南上。我正在寻找一个很好的资源,涉及以下主题:'C'项目体系结构指南的建议?

  1. 如何创建一个提升代码可维护性的接口,并且可用于将来的升级。
  2. 图书馆创作指南。例如,我应该何时考虑使用静态库和动态库。如何正确设计ABI来应对任何一个。
  3. 头文件:什么时候分区。关于什么时候使用1:1 vs 1:很多.h到.c的例子
  4. 任何你觉得我错过了但是在尝试构建一个新的C项目时很重要。

理想情况下,我希望看到一些示例项目,从小到大,并根据项目大小,功能或客户了解架构如何变化。

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

回答

10

每当我认真编写C代码时,我不得不在其中模拟C++特性。值得做的主要是:

  • 想象每个模块像一个类。你在头文件中公开的功能就像公共方法一样。如果它是模块所需接口的一部分,则只能在头中添加一个函数。

  • 避免循环模块依赖关系。模块A和模块B不应该互相呼叫。你可以将某些东西重构成模块C以避免这种情况。

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

  • 避免模块范围变量 - 前面描述的模式通常会做你所需要的。但是,如果你真的需要模块范围变量,将它们分组在一个存储在单个模块范围变量(称为“m”)中的结构或者一致的东西之下。然后在你的代码中,当你看到“m.variable”时,你一眼就能知道它是模块范围的结构之一。

  • 为了避免头文件的麻烦,将#ifndef MY_HEADER_H #define MY_HEADER_H声明,以避免包含double。标题。h文件为模块,应该只包含#include所需的头文件。模块.c文件可以包含编译模块所需的更多内容,但不要将这些内容添加到模块头文件中。这样可以避免大量的命名空间冲突和包含顺序问题。

+0

好的清单。另一件与标题相关的事情是确保每个标题都是独立的 - 它包含了它所需的任何标题,所以你可以包含它,而不必担心你需要什么。 – 2010-05-08 03:56:16

+2

Re:公共接口中的void指针 - 我更喜欢使用typedef处理的不透明结构。这样你就不必重新铸造,它提供了同样的实施保护。 http://en.wikipedia.org/wiki/Opaque_pointer#C – 2010-05-08 04:33:41

+0

同意Matt B.不要返回void *,请使用漂亮的typedef'd抽象数据类型。在我的示例中,在“以您最喜欢的语言实现一个类”的问题中:http://stackoverflow.com/questions/2702450/implement-a-simple-class-in-your-favorite-language/2771898#2771898 – 2010-05-08 10:10:13

3
  1. 从逻辑中分离演示代码。那是非常重要的
  2. 静态如果它们只用于您的项目或几乎没有二进制文件,动态多次使用(节省很多空间)。
  3. 无论何时多次使用代码,将其拆分为标题。

这些是我可以给你的一些我已知的技巧。

4

命名空间的清洁 - 对图书馆来说尤其重要。用某种方式在库的名称前面加上公用函数。如果你的图书馆被称为'开心乐园',那么做一些函数,比如“happyland_init”甚至“hl_init”。

这适用于静态。你将编写专门的函数 - 通过静态使用静态来隐藏它们。

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

6

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

  • 每个模块隐藏一个秘密。建立你的系统接口从他们的客户隐藏信息。 C唯一的类型安全的信息隐藏结构是指向不完整结构的指针。彻底学习并经常使用它。

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

  • 您需要命名约定。

如何在C中处理这些问题的绝佳模型是Dave Hanson的C Interfaces and Implementations。在这里你将会看到如何设计好的接口和实现,以及一个接口如何构建另一个接口来形成一个连贯的库。您还将获得一套出色的初始界面,您可以在自己的应用程序中使用它们。对于你所在职位的人,我不能太高度推荐本书。这是良好架构的系统在C

+0

+1代表CII。非常好的书,比一个更多的方式。 – 2010-05-08 05:00:59

3

原型如何创建 提升代码的可维护性,是 可扩展用于未来升级的接口。

通过暴露尽可能少的实现细节。例如,

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