Closed. This question needs details or clarity. It is not currently accepting answers. Learn more。
想改进这个问题吗?添加细节并通过editing this post澄清问题。
5年前关闭。
目前我正在写一个通讯协议库。对于此任务,我需要此结构:
但我该在哪里定义呢?我有一个“main”*.h文件,它包含在所有其他lib中。每个lib的*.c-文件只包括'parent'*.h-文件。结构类似于树:
孩子们总是包括他们的父母。但在一个库中,我得到一个错误,即类型未定义。
目前,它是在Main.h文件中声明的。但放在哪里最好?
然而,这不可能是全部的故事。创建一个头以在源文件之间共享声明;严格来说,仅包含一个文件的头是不必要的(尽管创建此类文件可能有合法的原因)。要么文件使用了在
对于库,您需要考虑的另一个方面是“库的客户端将如何使用代码?”这是至关重要的。客户端代码需要什么头?客户端代码需要什么函数?客户端代码是否需要任何类型定义?客户机代码需要访问C8B10结构的成员,还是只需要将其视为不透明类型?
您的外部头(库的客户机使用的头)应该尽可能小,但是是自包含的。假设外部头
在您的情况下,我希望
您可能会发现只有两个头文件更为合理—外部头文件
要记住的关键点是,头用于源文件之间的通信。其余的基本上是自动的。
想改进这个问题吗?添加细节并通过editing this post澄清问题。
5年前关闭。
目前我正在写一个通讯协议库。对于此任务,我需要此结构:
typedef struct _C8B10 {
unsigned int six :6;
unsigned int four :4;
} C8B10;
但我该在哪里定义呢?我有一个“main”*.h文件,它包含在所有其他lib中。每个lib的*.c-文件只包括'parent'*.h-文件。结构类似于树:
Main.h
Main.c
Child.h
Child.c
Child2.h
Child2.c
....
孩子们总是包括他们的父母。但在一个库中,我得到一个错误,即类型未定义。
目前,它是在Main.h文件中声明的。但放在哪里最好?
最佳答案
命名空间冲突
不管您做什么,都应该将结构标记从_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
或者两者都包含。对于库,您需要考虑的另一个方面是“库的客户端将如何使用代码?”这是至关重要的。客户端代码需要什么头?客户端代码需要什么函数?客户端代码是否需要任何类型定义?客户机代码需要访问C8B10结构的成员,还是只需要将其视为不透明类型?
您的外部头(库的客户机使用的头)应该尽可能小,但是是自包含的。假设外部头
child1.c
。如果客户机源代码在源文件中有main.h
作为第一个或唯一的头,则应编译头中的代码。例如,如果您的界面使用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.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
main.h
是否需要包含c8b10.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
中定义的外部可访问内容。这将导致:main.c
c8b10-private.h
c8b10.h
child1.c
c8b10-private.h
c8b10.h
child2.c
c8b10-private.h
c8b10.h
要记住的关键点是,头用于源文件之间的通信。其余的基本上是自动的。
关于c - 为库定义结构的最佳位置,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16781586/
10-10 23:24