我有遗留的c++代码,我应该删除不使用的代码。问题是代码库很大。

我如何才能知道哪些代码从未被调用/从未被使用?


当前回答

如果你使用g++,你可以使用这个标志-Wunused

根据文档:

Warn whenever a variable is unused aside from its declaration, whenever a function is declared static but never defined, whenever a label is declared but not used, and whenever a statement computes a result that is explicitly not used.

http://docs.freebsd.org/info/gcc/gcc.info.Warning_Options.html

编辑:这是另一个有用的标志-Wunreachable-code根据文档:

This option is intended to warn when the compiler detects that at least a whole line of source code will never be executed, because some condition is never satisfied or because it is after a procedure that never returns.

其他回答

对于未使用的整个函数(和未使用的全局变量),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),然后显式地选择你需要导出的导出函数。

你可以尝试使用Gimple Software的PC-lint/FlexeLint。它声称

找到未使用的宏,typedef, 类、成员、声明等。 贯穿整个项目

我曾用它进行静态分析,并发现它非常好,但我必须承认,我没有专门用它来查找死代码。

这取决于创建应用程序时使用的平台。

例如,如果你使用Visual Studio,你可以使用像. net ANTS Profiler这样的工具来解析和分析你的代码。通过这种方式,您应该很快知道实际使用了代码的哪一部分。Eclipse也有等效的插件。

否则,如果您需要知道最终用户实际使用了应用程序的哪些功能,并且您可以轻松地发布应用程序,则可以使用日志文件进行审计。

对于每个主要函数,您可以跟踪它的使用情况,并在几天/一周后获取日志文件,并查看它。

Mark as much public functions and variables as private or protected without causing compilation error, while doing this, try to also refactor the code. By making functions private and to some extent protected, you reduced your search area since private functions can only be called from the same class (unless there are stupid macro or other tricks to circumvent access restriction, and if that's the case I'd recommend you find a new job). It is much easier to determine that you don't need a private function since only the class you're currently working on can call this function. This method is easier if your code base have small classes and is loosely coupled. If your code base does not have small classes or have very tight coupling, I suggest cleaning those up first.

接下来将标记所有剩余的公共函数,并制作一个调用图,以找出类之间的关系。从这棵树上,试着找出树枝的哪一部分看起来可以修剪。

这种方法的优点是你可以在每个模块的基础上进行测试,所以当你的代码库损坏时,你很容易通过单元测试,而不会有很长一段时间。

我不认为它可以自动完成。

即使使用代码覆盖工具,也需要提供足够的输入数据来运行。

可能是非常复杂和昂贵的静态分析工具,如Coverity的或LLVM编译器可能会有所帮助。

但我不确定,我更喜欢手动代码审查。

更新

嗯. .不过,仅删除未使用的变量和未使用的函数并不难。

更新

看了其他人的回答和评论后,我更加坚定地认为这是不可能的。

您必须了解代码以获得有意义的代码覆盖率度量,如果您知道大量的手动编辑将比准备/运行/检查覆盖率结果更快。