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

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


当前回答

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

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

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

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

其他回答

真正的答案是:你永远无法真正确定。

至少,对于重要的情况,你不能确定你已经得到了全部。考虑以下来自维基百科关于不可达代码的文章:

double x = sqrt(2);
if (x > 5)
{
  doStuff();
}

正如维基百科正确指出的那样,一个聪明的编译器也许能够捕捉到这样的东西。但是考虑一下修改:

int y;
cin >> y;
double x = sqrt((double)y);

if (x != 0 && x < 1)
{
  doStuff();
}

Will the compiler catch this? Maybe. But to do that, it will need to do more than run sqrt against a constant scalar value. It will have to figure out that (double)y will always be an integer (easy), and then understand the mathematical range of sqrt for the set of integers (hard). A very sophisticated compiler might be able to do this for the sqrt function, or for every function in math.h, or for any fixed-input function whose domain it can figure out. This gets very, very complex, and the complexity is basically limitless. You can keep adding layers of sophistication to your compiler, but there will always be a way to sneak in some code that will be unreachable for any given set of inputs.

还有一些输入集是永远不会被输入的。输入在现实生活中没有意义,或者在其他地方被验证逻辑阻塞。编译器没有办法知道这些。

这样做的最终结果是,虽然其他人提到的软件工具非常有用,但您永远无法确定您捕获了所有内容,除非您随后手动检查代码。即便如此,你也无法确定自己是否错过了什么。

恕我直言,唯一真正的解决方案是尽可能保持警惕,使用自动化,尽可能地重构,并不断寻找改进代码的方法。当然,这样做是个好主意。

我有个朋友今天问了我这个问题,我看了看一些有前途的Clang开发,例如ASTMatchers和Static Analyzer,它们可能在编译过程中有足够的可见性来确定死代码部分,但后来我发现了这个:

https://blog.flameeyes.eu/2008/01/today-how-to-identify-unused-exported-functions-and-variables

它几乎完整地描述了如何使用一些GCC标志,这些标志似乎是为了识别未引用的符号而设计的!

我真的没有使用过任何工具做这样的事情…但是,就我所看到的所有答案,没有人说过这个问题是不可计算的。

这是什么意思呢?这个问题不能用计算机上的任何算法解决。这个定理(这样的算法不存在)是图灵停止问题的一个推论。

你将使用的所有工具都不是算法,而是启发式(即不是精确的算法)。他们不会给你所有没有使用的代码。

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

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

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

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

GNU链接器有一个——cref选项,用于生成交叉引用信息。你可以通过-Wl,——cref从gcc命令行传递它。

例如,假设foo。O定义了一个符号foo_sym,也在bar.o中使用。然后在输出中你会看到:

foo_sym                            foo.o
                                   bar.o

如果foo_sym限制为foo。O,那么你不会看到任何额外的目标文件;后面会跟着另一个符号:

foo_sym                            foo.o
force_flag                         options.o

现在,从这里我们不知道是否使用了foo_sym。它只是一个候选:我们知道它是在一个文件中定义的,而没有在其他任何文件中使用。Foo_sym可以在foo中定义。O和用于那里。

那么,你该怎么处理这些信息呢

执行一些文本修改,以识别限制在一个目标文件中的这些符号,生成候选列表。 进入源代码,给每个候选对象提供带有静态的内部链接,就像它应该有的那样。 重新编译源代码。 现在,对于那些真正未使用的符号,编译器将能够警告,为你精确定位它们;你可以删除它们。

当然,我忽略了其中一些符号是故意不使用的可能性,因为它们是为动态链接而导出的(即使在链接可执行文件时也可能出现这种情况);这是一种更微妙的情况,你必须了解并明智地处理。