假设我有一个正在构建的二进制文件,并且我包含了一堆从未实际使用过的文件,然后是否链接到这些包含文件描述的库?(同样,这些库从未使用过)
除了增加编译时间之外,这样做的负面后果是什么?
我能想到的一些是命名空间污染和二进制大小
除了编译时间;复杂性增加,调试时不必要的分心,维护开销。
除此之外,一无所有。
除了 Sasha 列出的还有维护成本。当您选择删除未使用的东西时,您是否能够轻松检测到将来使用的内容和未使用的内容?
如果这些库从未使用过,则可执行文件的大小不应增加。
根据具体的链接器,您可能还会注意到未使用库的全局对象仍会被构造。这意味着内存开销并增加了启动成本。
如果您包含但未使用的库不在目标系统上,即使它们不是必需的,它也无法编译。
这是我对有关 C 和静态库的类似问题的回答。也许它在 C++ 的上下文中也对您有用。
您提到了编译时间的增加。据我了解,这些库是静态链接的,而不是动态链接的。在这种情况下,这取决于链接器如何处理未使用的函数。如果它忽略它们,您将主要遇到维护问题。如果它们被包括在内,可执行文件的大小将会增加。现在,这比它在硬盘驱动器上占据的位置更重要。由于缓存问题,大型可执行文件可能会运行得更慢。如果exe中的活动代码和非活动代码相邻,它们将被缓存在一起,从而使缓存实际上更小,效率更低。
VC2005 及更高版本有一个称为 PGO 的优化,它以确保有效缓存经常使用的代码的方式对可执行文件中的代码进行排序。我不知道 g++ 是否有类似的优化,但值得研究一下。
这里对问题进行了一点汇编,必要时进行维基编辑:
主要问题似乎是:命名空间污染 这可能会导致未来的调试、版本控制出现问题,并增加未来的维护成本。
至少还会有次要的Binary Bloat,因为将维护函数/类/命名空间引用(在符号表中?)。动态库不应该大大增加二进制文件的大小(但它们会成为二进制文件运行的依赖项?)。从 GNU C 编译器来看,如果在源代码中从未引用静态链接库,则它们不应包含在最终二进制文件中。(基于 C 编译器的假设,可能需要澄清/纠正)
此外,根据库的性质,可能会实例化全局和静态对象/变量,从而增加启动时间和内存开销。
哦,增加了编译/链接时间。
当我在源代码树中编辑文件时,我发现它令人沮丧,因为我正在处理的某些符号出现在源文件中(例如,我刚刚更改了原型的函数名称 - 或者,可悲但更典型的是,只是将原型添加到标题中)所以我需要检查使用是否正确,或者编译器现在告诉我该文件中的使用不正确。所以,我编辑文件。然后我看到一个问题——这个文件在做什么?事实证明,尽管代码在产品中被“使用”了,但它实际上并没有被积极使用。
我在星期一发现了这个问题。一个包含 10,000 多行代码的文件调用了一个函数“extern void add_remainder(void);” 参数为 0。所以,我去修复它。然后我查看了其余的代码......原来它是大约 15 年前的一个开发存根,从未被删除。结果证明,干净地删除代码涉及对六个以上文件的微小编辑——而且我还没有弄清楚从枚举中间删除枚举常量是否安全,以防万一。暂时标记为“未使用/过时 - 可以安全移除吗?”。
在过去的 15 年中,该代码块的覆盖率为零——生产、测试……的确,它只是庞大系统的一小部分——按百分比计算,它不到图表上的 1%。尽管如此,这是额外浪费的代码。
令人费解。恼人的。令人沮丧的普遍(到目前为止,我已经记录并修复了今年至少六个类似的错误)。
并且浪费了我的时间——以及其他开发者的时间。多年来,其他人在做我正在做的事情——一项彻底的工作——定期编辑该文件。
我从来没有遇到过链接 .lib 文件的任何问题,该文件只使用了很小的一部分。只有真正使用的代码才会链接到可执行文件中,并且链接时间没有明显增加(使用 Visual Studio)。
如果您链接到二进制文件并且它们在运行时加载,它们可能会执行非平凡的初始化,这可以做任何事情,从分配少量内存到消耗稀缺资源以您不期望的方式改变模块的状态,以及超过。
你最好摆脱你不需要的东西,只是为了消除一堆未知数。
如果构建树没有得到很好的维护,它甚至可能无法编译。如果您在没有交换空间的嵌入式系统上编译。编译器在尝试编译大型目标文件时可能会耗尽内存。
它最近发生在我们的工作中。