为库定义结构的最佳位置

时间:2013-05-27 23:00:24

标签: c struct typedef

目前我正在为通信协议编写一个库。对于这个任务,我需要这个结构:

typedef struct _C8B10 {
    unsigned int six :6;
    unsigned int four :4;
} C8B10;

但我应该在哪里定义它?我有一个'main'* .h文件,包含在所有其他库中。每个lib的* .c文件仅包含'parent'* .h-file。结构类似于树:

Main.h
      Main.c
  Child.h
      Child.c
  Child2.h
      Child2.c
  ....

孩子们总是包含父母的Main.hchild.c。但是在一个库中我得到错误,没有定义类型。

目前它在Main.h文件中声明。但是把它放进去的最佳位置在哪里?

2 个答案:

答案 0 :(得分:2)

命名空间冲突

无论你做什么,都应该将结构标记从_C8B10更改为不会在为实现保留的命名空间上进行践踏的内容。

  

ISO / IEC 9899:2011

     

7.1.3保留标识符

     

¶1每个标头声明或定义其相关子条款中列出的所有标识符,和   可选地声明或定义其关联的未来库方向中列出的标识符   子条款和标识符,它们总是保留用于任何用途或用作文件   范围标识符。
   - 所有以下划线和大写字母或其他字母开头的标识符   下划线总是保留用于任何用途    - 始终保留以下划线开头的所有标识符作为标识符   在普通名称和标签名称空间中都有文件范围。

以下划线开头的名称存在风险;他们在那里为系统库的提供者。显然,如果你的图书馆是实施的一部分,这不适用于你,但我认为你不可能提出问题是否属于这种情况。

如果是我的代码,我只需删除下划线:typedef struct C8B10 { ... } C8B10;很好(typedef名称在普通标识符命名空间中,结构标记在tags命名空间中,两个不要冲突。)


头文件组织

您的图表与大多数人通常编写此类图表的方式相反。源代码包含标题,因此可能将其图示为:

main.c
    main.h
child1.c
    child1.h
child2.c
    child2.h

然而,这不可能是整个故事。您创建一个标题来共享源文件之间的声明;一个文件只包含一个标题并不是绝对必要的(虽然创建这样的文件可能有合法的原因)。文件main.c使用child1.c中定义的某些函数(和类型 - 可能是宏甚至全局变量,消除思想)或child1.c中的代码使用main.c中的材料{1}}(或可能两者)。因此,main.c应包含child1.hchild1.c应包含main.h或两者。

您需要考虑使用库的另一个方面是“库的客户端如何使用代码?”这很关键。客户端代码需要什么标头?客户端代码需要哪些功能?客户端代码是否需要任何类型定义?客户端代码是否需要访问C8B10结构的成员,或者他们是否只需将其视为不透明类型?

您的外部标题 - 库的客户端使用的标题 - 应该尽可能小,但是自包含。我们假设外部头是c8b10.h。如果客户端源代码具有#include "c8b10.h"作为源文件中的第一个或唯一标头,则标头中的代码应该编译。例如,如果您的界面使用size_t,则需要#include <stddef.h>中的c8b10.h

在您的情况下,我希望您的C8B10结构应在main.h中定义,而child1.cchild2.c都应包含main.hmain.c可能还应包含child1.hchild2.hmain.h应包含外部c8b10.h标头,因此实际上每个文件都包含该标头。

main.c
    main.h
        c8b10.h
    child1.h
    child2.h
child1.c
    main.h
        c8b10.h
    child1.h
child2.c
    main.h
        c8b10.h
    child2.h

child2.c是否需要包含child1.h以及child1.c是否需要包含child2.h取决于代码的编写方式以及每个文件提供的服务其中。

您可能会发现只有两个标头更为明智 - 外部c8b10.h标头和一个内部标头c8b10-private.hc8b10-private.h标头将包含在库中的每个源文件中。它将包含的第一个标头是外部c8b10.h标头(以帮助自动检查c8b10.h标头是否自包含)。 c8b10-private.h标头将对应main.hchild1.hchild2.h的合并,减去c8b10.h中定义的外部可访问内容。这导致:

main.c
    c8b10-private.h
        c8b10.h
child1.c
    c8b10-private.h
        c8b10.h
child2.c
    c8b10-private.h
        c8b10.h

要记住的关键点是标题用于源文件之间的通信。其余部分主要是自动完成的。

答案 1 :(得分:1)

头文件通常像Java的接口一样使用,因为头文件定义了实现之外可用的信息。

如果结构应该在实现之外可用,请在标头中定义它,否则在.c文件中将其定义一次,该文件包含在其他.c文件中。