我有遗留的c++代码,我应该删除不使用的代码。问题是代码库很大。
我如何才能知道哪些代码从未被调用/从未被使用?
我有遗留的c++代码,我应该删除不使用的代码。问题是代码库很大。
我如何才能知道哪些代码从未被调用/从未被使用?
当前回答
你可以尝试使用Gimple Software的PC-lint/FlexeLint。它声称
找到未使用的宏,typedef, 类、成员、声明等。 贯穿整个项目
我曾用它进行静态分析,并发现它非常好,但我必须承认,我没有专门用它来查找死代码。
其他回答
如果你使用g++,你可以使用这个标志-Wunused
根据文档:
每当变量未使用时发出警告 除了它的声明,无论何时 函数被声明为静态的,但是 从来没有定义,每当一个标签 声明但未使用,并且每当a 语句计算的结果为 明确没有使用。
http://docs.freebsd.org/info/gcc/gcc.info.Warning_Options.html
编辑:这里是另一个有用的标志-Wunreachable-code 根据文档:
此选项用于在编译器检测到至少一整行源代码永远不会执行时发出警告,因为某些条件永远不会满足,或者因为它在一个永远不会返回的过程之后。
更新:我在遗留的C/ c++项目中发现了类似的主题死代码检测
If you are on Linux, you may want to look into callgrind, a C/C++ program analysis tool that is part of the valgrind suite, which also contains tools that check for memory leaks and other memory errors (which you should be using as well). It analyzes a running instance of your program, and produces data about its call graph, and about the performance costs of nodes on the call graph. It is usually used for performance analysis, but it also produces a call graph for your applications, so you can see what functions are called, as well as their callers.
这显然是对页面其他地方提到的静态方法的补充,它只会有助于消除完全不使用的类、方法和函数——它不会帮助找到实际调用的方法内部的死代码。
你可以尝试使用Gimple Software的PC-lint/FlexeLint。它声称
找到未使用的宏,typedef, 类、成员、声明等。 贯穿整个项目
我曾用它进行静态分析,并发现它非常好,但我必须承认,我没有专门用它来查找死代码。
对于未使用的整个函数(和未使用的全局变量),GCC实际上可以为您完成大部分工作,前提是您使用GCC和GNU ld。
编译源代码时,使用- function-sections和-fdata-sections,然后链接时使用-Wl,——gc-sections,——print-gc-sections。链接器现在将列出所有可以删除的函数,因为它们从未被调用,以及所有从未被引用的全局函数。
(当然,你也可以跳过——print-gc-sections部分,让链接器无声地删除函数,但将它们保留在源代码中。)
注意:这只会发现未使用的完整函数,它不会对函数中的死代码做任何事情。在活函数中从死代码调用的函数也将被保留。
一些c++特有的特性也会导致问题,特别是:
Virtual functions. Without knowing which subclasses exist and which are actually instantiated at run time, you can't know which virtual functions you need to exist in the final program. The linker doesn't have enough information about that so it will have to keep all of them around. Globals with constructors, and their constructors. In general, the linker can't know that the constructor for a global doesn't have side effects, so it must run it. Obviously this means the global itself also needs to be kept.
在这两种情况下,虚函数或全局变量构造函数使用的任何东西都必须保留。
另外需要注意的是,如果您正在构建一个共享库,GCC中的默认设置将导出共享库中的每个函数,导致只要链接器就会“使用”它。为了解决这个问题,你需要将默认值设置为隐藏符号而不是导出(例如使用-fvisibility=hidden),然后显式地选择你需要导出的导出函数。
一种方法是使用调试器和编译器特性,在编译过程中消除未使用的机器代码。
一旦某些机器代码被删除,调试器就不会让你在相应的源代码行上添加断点。因此,您将断点放置在任何地方,并启动程序并检查断点——那些处于“此源未加载代码”状态的断点对应于已消除的代码——要么该代码从未被调用,要么已内联,您必须执行一些最小分析,以找出这两者中哪一个发生了。
至少这是它在Visual Studio中的工作方式,我猜其他工具集也可以做到这一点。
这需要做很多工作,但我认为比手动分析所有代码要快。