解开头文件依赖关系

4
当你有一组.h文件陷入了经典的“戈尔迪亚之结”情况时,该怎么办?如果要#include一个.h文件,就几乎要包含所有文件。预防显然是最好的药物,但当厂商(!)未发货库时,该怎么办?
这里有一个问题的延伸,也许更为重要-- 你是否应该尝试首先解开依赖关系?

+1,我也有类似的问题。 - Naveen
4个回答

5
我曾经在一个已经分成许多库的C++代码库上进行了这项工作(这是一个不错的开始)。
我必须找出(或猜测)哪个库是最依赖于其他代码库中的内容的,然后逐个处理每个库。
我逐个查看每个模块(*.cpp文件),确保它自己的头文件被首先#include,并注释掉其余部分,然后注释掉该头文件中的所有#include语句,然后重新编译该模块,让编译器告诉我需要什么。我会取消注释似乎需要的第一个头文件,并进行审核,必要时递归。有趣的是,看到有多少头文件最终不需要。
当只需要名称(因为您有指针或引用)时,请使用class name;或struct name;,这称为前向声明,并避免#include头文件。
当您注释掉#include语句时,编译器非常有帮助地告诉您依赖关系(您需要使用所有编译器重新编译以保持可移植性)。
有时我不得不将模块移动到库之间,以便没有一对或一组库相互依赖。

头文件中使用前向声明,实现文件中使用完整的包含。 - CiscoIPPhone

1

如果你有机会的话,应该重构代码以减少过大的包含文件,但这需要做到某种程度的包内聚。如果你将所有东西分离开来,只是发现代码的每个用户仍然必须包含所有元素,那么最终结果是相同的。

另一个选择是使用 #define 来配置部分开关。无论如何,对于现有的代码库,解决方案是朝着包内聚的方向发展。

阅读:http://ivanov.files.wordpress.com/2007/02/sedpackages.pdf 并研究与包内聚相关的问题。


1

我已经多次解开了那个困扰,通常在维护系统时尽量减少.h文件的依赖会有很大帮助。有一些不错的工具可以生成依赖树(当时我在使用Klocwork)。

我发现的一个缺点是条件编译。有人可能会移除一个头文件,因为他们认为我们不需要它,但事实上我们之所以不需要它是因为VxWorks有一些混乱的头文件... 在Solaris(或任何合理的Posix系统)上你确实需要它。


0

在精细组织的大量头文件和包含所有内容的单个头文件之间需要取得平衡。考虑标准C库;有一些较大的头文件,如<stdio.h>,它声明了许多函数,但它们都与I/O相关。还有其他一些头文件是杂项 - 特别是<stdlib.h>

戈达德航天飞行中心的C语言指南值得寻找。

基本规则是每个头文件应声明由适当(通常很小)的一组源文件提供的设施。这些设施和头文件应该是自包含的。也就是说,如果有人需要头文件"something.h"中的代码,则必须将其作为唯一必须添加到编译中的头文件。如果"something.h"需要的设施在头文件中没有声明,则必须包括相关的头文件。例如,这可能意味着头文件最终包括<stddef.h>,因为其中一个函数使用了size_t

正如@quamrana所指出的那样,当适用时,您可以为结构体(而不是类,因为问题标记为C而不是C++)使用前向声明——这主要意味着当接口需要指针但不需要知道结构体或任何成员的大小时。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接