如何理解大型复杂模块,"没有"编译和调试它

时间:2014-11-02 09:48:33

标签: c++ c code-analysis

我有多个文件的大模块,这个模块没有文档,没有正确的注释,而且非常复杂......它也有可怕的变量名(比如int x,char y ...等)

我会使用调试器和断点来查看模块的流程,但是我没有完整的系统来编译这个模块。

所以我现在必须依赖源代码本身。

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

文档 ,并根据其实际行为进行验证。

答案 1 :(得分:1)

您可以使用以下两种基本方法之一:自下而上或自上而下。

  • 自下而上,您首先尝试查找自包含的函数。 I. e。不调用模块中其他功能的功能。它们可以调用标准库函数或递归,但除此之外,它们只与数据交互。尝试掌握它们的含义(并添加相应的注释,然后转到使用您已经理解的函数的函数。

    问题在于,用这种方法很难全面了解。

  • 使用自上而下,您首先尝试识别模块的接口功能。应该从外部调用的函数。然后你试着猜测它们的意图,并试图推导出它们如何使用内部函数来实现它们的目标。这允许您导出这些内部函数的作用,并且可以递归调用树。这与您的调试器方法非常相似。

    问题在于,可能很难确定哪些功能是接口功能。许多(大多数)库/模块不必在界面和内部函数之间进行辨别,生成的.so文件会导出所有符号。但是,开发人员可能已将所有接口函数收集到一个大标题中。如果是这种情况,您可以从中获得一个现成的完整的界面功能列表。

我通常尝试将这两种方法结合起来,从上到下开始,然后深度搜索自我包含的函数,我可以完全理解。这是将目的信息与内部工作信息相结合的最快方法。


理解代码的另一个非常重要的工具可能是重构。当我不得不把自己读成一个包含超过50行代码的函数时,几乎不可避免的是,在我理解它之后,它不再超过50行。

在这些情况下,我尝试在函数中识别相对自包含的部分,尝试理解它们的作用,并将它们分解为它们自己的函数。另一种启发式方法是查找重复代码,可以将其分解为一个使用不同参数调用的函数。一旦一个函数被分解出来,你知道它做了什么,并且你有一个有意义的名字,这使得长函数的其余部分更容易理解。并且用它来减少长函数的结构复杂性。

使用这种重构方法时,限制自己只做一些可以证明他们不会改变可见行为的更改是非常重要的:你还没有完全理解代码,所以如果你做了非平凡的事情改变,你真的搞砸了。