假设有三个标题AAA.h
,BBB.h
和MyLib.h
。 MyLib.h
需要同时包含AAA.h
和BBB.h
才能正常运作。
现在,恰好BBB.h
中还包含AAA.h
,但这完全取决于实施,MyLib.h
不应该关注的细节。
然而,错误地,MyLib.h
的作者忽略了包括AAA.h
而从未注意到。据我所知,这通常不会导致错误或警告。稍后,有人会更改BBB.h
的实施细节,以便不再需要AAA.h
,从而将其删除。现在MyLib没有编译,因为库BBB的内部已经改变了。
在这些情况下,有没有办法出错或发出警告?我怀疑(如果这是可能的话)它将在包含的标题中采用某种注释。
答案 0 :(得分:2)
您正在说明为什么包含标题作为导入名称空间的方法很糟糕。
我看到的唯一解决方案是纪律。标准库函数要求您包含相应的标题,您的项目应采用相同的标准。 MyLib.h
之类的标题应仅包含它定义的类型及其函数原型。如果它需要使用某种类型来完成它的工作,那么应该明确地包含标题,所以如果它需要来自AAA
的定义,它应该包含AAA.h
,如果需要来自{{1}的定义它应该包含BBB
,同样任何实现文件(假设BBB.h
)都应明确包含它使用的任何定义的所有标头,而不管是否MyLib.c
将它们包括在内好。 永远不要假设标题通过包含其他标题来隐式定义任何内容。
使用IDE可以轻松检查,这通常会告诉您名称的定义位置,因此您可以轻松找出要使用的包含文件。可能有工具可以进行这种检查。
答案 1 :(得分:2)
我认为最好避免依赖公共接口标头中的其他标头,以免出现此问题。
公共接口标头不应包含不必要的定义。
在没有包含文件的情况下,有各种各样的技巧。例如,如果您只需要一个指针(仅定义typedef的库,那么您可以手动声明struct标签),并且可以使用_Bool
代替bool
来避免<stdbool.h>
。遗憾的是,许多重要类型(例如size_t
和uint32_t
)仅在标题中定义。
有些软件包甚至使用configure定义自己的foo_uint32_t
,因此他们不需要在公共接口头中包含<stdint.h>
。这非常棘手,因为类型必须完全相同才能避免混淆:即使sizeof(unsigned int) == sizeof(unsigned long) == 4
它们是不同的类型。因此,它可能不值得。