不同的编译器如何处理可证明未使用的实体

2020-12-04 22:49:05

前几天,有人问我是否应该担心代码库中未使用的函数所占用的空间。我的回答遵循以下漫漫路径:

未使用的功能模板甚至都不会实例化,因此它们在链接时实际上不存在。

可以使用未使用的内联函数进行代码生成,但是如果启用了编译器优化功能,则除非实际调用内联函数,否则您可能看不到任何内联函数的代码源。

从逻辑上讲,应该对未使用的静态非成员函数进行代码生成,但是由于静态函数在其自身的TU之外是不可见的,因此编译器可能能够检测并警告它们-并且在启用编译器优化的情况下,编译器可能会决定也没有理由为他们生成代码。

但是,未使用的非静态(外部链接)功能必须进行代码生成,因为编译器无法证明没有其他TU调用它们。一个优化的链接器可能能够证明没有人需要这些定义,并消除它们—我亲自设计了一个完全实现该优化的链接器—但是总的来说,您对链接器的思维模型应该是不会进行该优化的。

链接器很可能能够证明该功能尚未使用;但是,如果没有编译器的某种帮助,它就可能无法证明仅从文本部分剪切该函数的字节是安全的。这可能会弄乱目标文件其余部分秘密依赖的相对偏移量。

从逻辑上讲,未使用的私有(非静态)数据成员必须占用该类的内存占用空间,以便每个TU都同意该类的大小。但是,如果编译器可以在某个特定的TU中看到该类的每个成员和每个朋友的完整定义,则可以证明私有成员确实未被使用,然后可以发出警告。 lang做这件事。

嗯,但是Clang仅针对私有数据成员执行此操作,而不针对私有成员函数执行此操作! 那很有意思! 这是您可能会遇到的非二倍体非内联实体的完整列表,以及主要编译器对它们的证明(如果被证明未使用)会如何处理。 (天哪。) 选项方面,我在MSVC上测试了-W1-W2 -W3 -W4 -Od -O1 -O2,在其他三个测试了-Wall -Wextra -O0 -O1 -O2 -O3。 还是我错过了一些微妙的机制,实际上可能会从其他TU引用“未使用的”私人成员? 我在表单元格中放置了“ –”,在该单元格中,此漏洞使得建议的优化在技术上对于合规的编译器是不可能的。 所有编译器的诊断程序都可以使用改进,但是新的优化表显示,每个人(MSVC除外)在优化方面都尽了最大的努力。