use*_*898 310 c++ optimization dead-code
我有遗留的C++代码,我应该从中删除未使用的代码.问题是代码库很大.
如何找出从未调用/从未使用过的代码?
Mat*_* M. 196
有两种未使用的代码:
对于第一种,一个好的编译器可以帮助:
-Wunused(GCC,Clang)应警告未使用的变量,Clang未使用的分析器甚至已经增加,以警告从未读过的变量(即使使用过).-Wunreachable-code(较旧的海湾合作委员会,2010年被删除)应该警告从未访问的本地区块(它发生在早期返回或总是评估为真的条件)catch块,因为编译器通常无法证明不会抛出任何异常.对于第二种,它要困难得多.静态地,它需要整个程序分析,并且即使链接时间优化实际上可以去除死代码,实际上程序在执行时已经被大量转换,几乎不可能向用户传达有意义的信息.
因此有两种方法:
gcov.注意,在编译期间应该传递特定的标志,以使其正常工作).您使用一组良好的输入(单元测试或非回归测试)运行代码覆盖率工具,死代码必须在未到达的代码中...所以您可以从这里开始.如果您对该主题非常感兴趣,并且有时间和倾向自己实际制定工具,我建议使用Clang库来构建这样的工具.
因为Clang将为您解析代码并执行重载解析,所以您不必处理C++语言规则,并且您将能够专注于手头的问题.
但是,这种技术无法识别未使用的虚拟覆盖,因为它们可能被您无法推理的第三方代码调用.
小智 34
对于未使用的整个函数(以及未使用的全局变量)的情况,GCC实际上可以为您完成大部分工作,前提是您正在使用GCC和GNU ld.
编译源代码时,使用-ffunction-sections和-fdata-sections,然后在链接时使用-Wl,--gc-sections,--print-gc-sections.链接器现在将列出可以删除的所有函数,因为它们从未被调用,并且所有从未引用过的全局变量.
(当然,您也可以跳过该--print-gc-sections部分,让链接器以静默方式删除这些函数,但将它们保留在源代码中.)
注意:这只会找到未使用的完整函数,它不会对函数内的死代码做任何事情.在实时函数中从死代码调用的函数也将被保留.
某些特定于C++的功能也会导致问题,特别是:
在这两种情况下,虚拟函数或全局变量构造函数使用的任何东西也必须保持不变.
另一个警告是,如果您正在构建共享库,GCC中的默认设置将导出共享库中的每个函数,从而导致它被"使用",就链接器而言.要解决此问题,您需要将默认值设置为隐藏符号而不是导出(使用eg -fvisibility=hidden),然后显式选择需要导出的导出函数.
Umm*_*mma 25
好吧,如果你使用g ++,你可以使用这个标志 -Wunused
根据文件:
每当变量是未使用的除了其声明中,每当函数声明为static但从定义,每当声明了标号但未使用,每当一个语句的计算是明确不使用的结果.
http://docs.freebsd.org/info/gcc/gcc.info.Warning_Options.html
编辑:这是其他有用的标志-Wunreachable-code
根据文件:
此选项旨在警告当编译器检测到至少源代码的整条生产线将不会被执行,因为某些条件是永远不会满足,或者因为它是永远不会返回的过程之后.
更新:我在遗留的C/C++项目中发现了类似的主题死代码检测
Car*_*s V 18
我认为您正在寻找代码覆盖工具.代码覆盖工具将在代码运行时对其进行分析,它将让您知道执行了哪些代码行以及执行了哪些代码行以及哪些代码行未执行.
你可以尝试给这个开源代码覆盖工具一个机会:TestCocoon - C/C++和C#的代码覆盖工具.
Jus*_*gan 15
这里真正的答案是:你永远不会真正知道.
至少,对于非常重要的案例,你不能确定你已经掌握了所有这些.请阅读Wikipedia关于无法访问代码的文章中的以下内容:
double x = sqrt(2);
if (x > 5)
{
doStuff();
}
Run Code Online (Sandbox Code Playgroud)
正如维基百科正确指出的那样,一个聪明的编译器可能能够捕获这样的东西.但考虑修改:
int y;
cin >> y;
double x = sqrt((double)y);
if (x != 0 && x < 1)
{
doStuff();
}
Run Code Online (Sandbox Code Playgroud)
编译器会抓住这个吗?也许.但要做到这一点,它需要做的不仅仅是sqrt针对恒定的标量值.它必须弄清楚(double)y总是一个整数(简单),然后理解sqrt整数集(硬)的数学范围.一个非常复杂的编译器可能能够为sqrt函数或math.h中的每个函数执行此操作,或者为其可以找出其域的任何固定输入函数执行此操作.这变得非常非常复杂,复杂性基本上是无限的.您可以继续为编译器添加复杂的层次,但总会有一种方法可以隐藏某些代码,这些代码对于任何给定的输入集都是无法访问的.
然后有输入集,根本就没有输入.输入在现实生活中没有意义,或被其他地方的验证逻辑阻止.编译器无法知道这些.
最终的结果是,虽然其他人提到的软件工具非常有用,但你永远不会知道你抓住了一切,除非你之后手动完成代码.即便如此,你永远不会确定你没有错过任何东西.
唯一真正的解决方案,恕我直言,要尽可能保持警惕,使用自动化,重构你可以,并不断寻找改进代码的方法.当然,无论如何都要做到这一点是个好主意.
您可以尝试使用Gimple Software的PC-lint/FlexeLint.它声称
在整个项目中查找未使用的宏,typedef,类,成员,声明等
我已经将它用于静态分析并发现它非常好但我不得不承认我没有用它来专门找到死代码.
我找到未使用的东西的正常方法是
watch "make 2>&1"倾向于在 Unix 上做到这一点。这是一个有点漫长的过程,但它确实给出了很好的结果。
| 归档时间: |
|
| 查看次数: |
48059 次 |
| 最近记录: |