命名空间冲突
无论您做什么,都应该将结构标记_C8B10
从不践踏为实现保留的命名空间。
ISO/IEC 9899:2011
7.1.3 保留标识符
¶1 每个标头声明或定义其相关子条款中列出的所有标识符,并可选地声明或定义其相关未来库方向子条款中列出的标识符和标识符,这些标识符始终保留用于任何用途或用作文件范围标识符。
— 以下划线和大写字母或另一个下划线开头的所有标识符始终保留用于任何用途。
— 所有以下划线开头的标识符始终保留用作普通和标记名称空间中具有文件范围的标识符。
下划线开头的名字是有风险的;它们是为系统库的提供者而存在的。显然,如果您的库是实现的一部分,那么这不适用于您,但我认为如果是这种情况,您不太可能会问这个问题。
如果是我的代码,我会简单地去掉下划线:typedef struct C8B10 { ... } C8B10;
是好的(typedef
名称在普通标识符命名空间中,结构标签在标签命名空间中,两者不冲突)。
头文件组织
您的图表与大多数人通常编写此类图表的方式相反。源代码包括标题,因此它可能被图示为:
main.c
main.h
child1.c
child1.h
child2.c
child2.h
然而,这不可能是全部。您创建一个标头以在源文件之间共享声明;仅由一个文件包含的标头并非绝对必要(尽管创建此类文件可能有正当理由)。要么文件main.c
使用了其中定义的一些函数(和类型——可能是宏甚至全局变量,别想了),child1.c
要么代码child1.c
使用来自main.c
(或可能两者)的材料。因此,要么main.c
应该包括,child1.h
要么应该child1.c
包括,main.h
或者两者兼而有之。
对于库,您需要考虑的另一个方面是“库的客户将如何使用代码?” 这是至关重要的。客户端代码需要什么标头?客户端代码需要哪些功能?客户端代码是否需要任何类型定义?客户端代码是否需要访问 C8B10 结构的成员,还是只需将其视为不透明类型?
你的外部头文件——库的客户使用的头文件——应该尽可能小,但自包含。假设外部标头是c8b10.h
. 如果客户端源代码具有#include "c8b10.h"
作为源文件中的第一个或唯一的标头,则标头中的代码应该编译。size_t
例如,如果您#include <stddef.h>
的界面使用c8b10.h
.
在您的情况下,我希望您的C8B10
结构应该在main.h
和两者中定义,child1.c
并且child2.c
应该包括main.h
. 很可能main.c
还应该包括child1.h
和child2.h
。并且main.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.h
。标c8b10-private.h
头将包含在库中的每个源文件中。它将包含的第一个标头是外部c8b10.h
标头(以帮助自动检查c8b10.h
标头是否自包含)。标c8b10-private.h
头将对应于 和 的合并,main.h
减去中定义的外部可访问内容。这将导致:child1.h
child2.h
c8b10.h
main.c
c8b10-private.h
c8b10.h
child1.c
c8b10-private.h
c8b10.h
child2.c
c8b10-private.h
c8b10.h
要记住的关键点是标头用于源文件之间的通信。其余的大部分都是自动的。