未使用代码的开销

时间:2011-05-26 11:10:39

标签: c++ function compiler-construction linker overhead

我想知道在代码中使用未使用的函数会产生什么样的开销。

比如说你有一些调试日志记录,然后你给大多数对象一个在调试日志中使用的ToString()函数。

在发布版本中,未使用调试日志记录。是否值得删除那些ToString()函数的源代码? (例如通过宏?)

或者他们只是使可执行文件略大,否则不会影响性能?例如没有速度影响?或者,如果不使用它们,编译器或链接器是否甚至可以删除它们?如果编译器或链接器没有删除代码,那么如果ToString()函数是内联定义的呢?据推测,它会尝试内联代码,并且由于函数永远不会被调用,它会消失吗?

我想每个函数都需要保留在静态库中,但是一旦编译成可执行文件,链接器肯定会忽略很多东西吗?

另一个注意事项大致相似,如果编译器选择不内联内联函数,以便内联函数在几个编译单元中被定义为函数,那么链接器会丢弃多余的定义并仅链接其中一个最后?

由于

4 个答案:

答案 0 :(得分:5)

这取决于编译器,我想是优化级别。

G ++和MSVC ++删除未使用的内联函数,但保留未使用的非内联函数。 例如,在正常程序中只使用STL的一小部分。删除所有未使用的函数,因为它们被定义为内联函数。

另一方面,GCC保留所有功能,甚至是未使用的内联功能。

回答你的另一个问题:如果函数以多种方式在多个编译单元中定义,链接器将皱眉并拒绝链接,除非它被定义为内联。

答案 1 :(得分:3)

1。关于编译器和链接器

这取决于您创建可执行文件的方式。

通常,可执行文件会被删除任何未使用的内容。因此,如果您静态链接(以及使用正确的优化选项),函数将被删除。

但是,如果你动态链接,它们就会存在,因为就库而言,它们会被导出并因此被使用。

对于多个定义,它取决于符号是否弱。如果它很弱,链接器会选择其中一个定义,否则就会扼杀它。

最后,它们可能只代表程序的边缘部分。

2。如何解决这个问题?

这是一个很难的问题,你总是可以使用预处理器来删除一些东西,但是用预处理程序指令填充的代码实际上很烦人。

就个人而言,我不会打扰...尤其是因为我也登录了Release(如何跟踪生产问题?)。

解决方案可能是在单独的文件中定义违规函数,而不是在Release中链接它们。 注意:我认为它不适用于虚拟功能,因为它们至少在vtable中使用

答案 2 :(得分:2)

链接器会删除重复的功能,但它们会删除未引用的数据(Microsoft链接器提供/OPF:REF/OPT:ICF开关来调整这些设置。

你肯定是对的,在大多数情况下,链接器是否能够很好地删除不需要或冗余的东西 - 对于一些小函数对可执行文件大小的影响(与如果大量使用STL或其他模板库,生成的大量代码是最小的。

也就是说,如果您需要尽可能小的可执行文件(或者如果您发现调试代码真的占用了大部分图像大小),#ifdef一切是强制执行某些不包含的功能的最简单方法。它使得代码有点难看,但它的优点是你不会在发布版本中意外遗漏调试代码的几个点,因为任何调用不存在的函数的尝试都会导致编译器错误。

#ifdef的另一个优点是它是可移植的,不依赖于特定的编译器系统: - /

答案 3 :(得分:0)

如果您将非虚拟功能放在库中的单独文件中,并且 静态链接,如果是,则只应添加到可执行文件中 用过的。但唯一真正的区别在于它的大小 可执行文件;这可能会影响到地方,因此 表演,但如果它真的有所作为,我会感到非常惊讶 在实践中。所以一般来说,我会说这种技术不值得 在应用程序中烦恼。 (如果您要提供第三方库, 另一方面,你绝对想要一个非虚拟功能 单独的文件。)