代码解析技术

 

代码解析技术

By青木峰郎 translated by 东北藏

 

本文写作动机

经常听到请读一下代码读代码等诸如此类的话,却没有见过有人写出怎样能读好代码的文章。是不是既然是程序员就理所当然知道程序的阅读技巧了呢?

但谁都不能否认读懂别人写的代码绝对不是件轻松的事。其实读代码不但是必要的,跟写代码一样也有技术或模式可言。那么,代码应该怎么读呢?以C语言为前提,不知不觉总结了些明确的东西。

方针的决定

确定了要读的程序,应该怎么做呢?什么方针也没有只是一味地从main开始读,因该很难读懂程序的意思吧。首先要明确读程序的目的,专注于此。所有程序都必须读时,要分解成一部分一部分来读。

解析的手法

解析手法大概可以分为静态手法和动态手法两类。所谓静态手法就是指只读程序本身。而动态手法是通过使用调试等分析程序运行时的动的一面。

一般的解析应从动态解析开始为宜。静态解析或多或少是想象程序的动作的。与此相对的动态解析,看到的即是事实的东西。首先从事实出发很容易找到方向,同时也减少了错误。这与在最优化前要取得特性的描述有相似之处吧。或者也可以说成,事件的解决最好从现场开始。

静态解析

◇使用对象程序

没有程序就无从下手。首先必须清楚是什么程序,程序是怎么动作的。

读文档

这与上一项比较相似,必须先知道规格。如果有内部结构的说明材料,也一定要读一下。要检查一下是否有HACKINGTOUR等为名字的文件。

读路径结构

看看路径是以怎样的方针构成的。程序是怎么作的,都有哪些部分,要把握这样的概要。确定一下各个模块之间都有哪些关系。

读文件构成

看看文件是以怎样的方针组成的,同时要分析一下文件中的函数。文件名就像是注释的内容一样,要引起重视。

试着找出函数名的命名规则。如果是C程序,对extern函数应该使用了前缀,这种前缀用来区分函数的种类。如果是面向对象的程序,前缀通常表明函数的所属信息,属于重要信息。(例:rb_str_push

省略语的调查

要列出很难理解的省略语,及早调查。比如GC的意思是garbage collection呢还是graphic context呢,意思差的很大。使用英语单词的场合经常有只取字头,或省略母音的情况。特别是要是调查好在对象程序的特定应用领域中常用的省略语。

笔者仅举一个记着的例子。某个Lisp应用中,程序中使用了很多blt这个前缀,究竟是什么意思一直困惑不解。这实际上是built-in function (嵌入式函数)的意思。明白的话可能觉得没什么,可是不理解的话对程序的把握就增加了相当的难度。

弄清楚数据结构

因为是程序,了解了数据结构的话就基本可以说读懂了一半。写程序时也是一样,对数据结构的说明远比对程序逐行注释更具价值。(这句话好像在那本书里写的,哪本书呢。)

 

补充: 程序书法一书。以下摘自p.168对程序的注释的最有效的方法之一是:对数据的使用的解释。对主要的变量若能做出可能是什么样的值以及值是怎样变化的解释的话,但这一点就可认为是很不错的注释了。

这本书是1974年出版的。

补充2C程序诊断室一书中也有类似的论述。以下摘自p.78放弃使用流程图吧。流程图是反映控制流程的,所以它不好。程序是处理数据的,数据不同控制的流程就不同。要记住,数据永远是主体。对变量及参数等数据的有效定义与使用能大幅度地改善程序的组织。所以数据构造图比流程图更具价值。一定要写清楚数据是什么意思!

休闲话题:C语言中的数据结构通常是指使用structunion。这些重要的数据结构通常定义在头文件中。当然内部结构定义在.c中以及也有动态构建数据结构的情况,不最终读函数就不清楚。即使这样也应该从头文件读起。读头文件时文件名就显得重要了,比如frame.h这样的文件,应该是staff frame的定义。

猜想数据结构时要注意结构体成员。结构体的定义中若有next指针就应该判断为链表。同样,存在parentchildrensibling这样的要素的话,十之八九是树结构。

把握函数之间的调用关系

除了函数名这也是一种重要的信息。特别是函数数目多的时候就更显得重要了。这里应该使用工具,能有做成图的工具当然好,没有的话把最重要的部分自己画一画。没有必要在画图上花费太长时间,在纸的背面简单画些草图足以。

用图来显示函数之间的调用关系叫做调用图(call graph)。仅反映程序中函数之间调用关系的图称为静态调用图(static call graph),反映实际运行时函数之间的调用关系的图称为动态调用图(dynamic call graph)

但是,经过检索发现,日语的文章中call graph通常指dynamic call graph,而static call graph通常指函数间调用关系。但是因为staticdynamic对应起来容易理解,笔者就称为动态调用图和静态调用图。

读函数

读函数的动作。最好一边读函数关联图,一边一部分一部分地理解。传统的自上而下式的程序应该从main开始,与GUI相似的在主循环中不停循环的程序以回调(CallBack)为顺序来把握。这主要取决于函数之间的关系。

这里,要使用调查关键词的定义位置的工具(见后述)。如前所述,定义函数及变量的函数名本身就包含了分类等重要信息。

同时,读程序之前要考虑不读什么。不管以何种手段,全读的话会花费大量时间。错误处理,不要的分支,基本达不到的情况要略过。防御处理作的很好的话,这部分工作相对比较容易。反之,要让这部分很轻松就要使用异常等防御处理。

随心所欲来替换

这 并不是一个解析的阶段,而是一种手法。人类的头脑真是不可思议,为了加深记忆充分利用了身体的各个部分。很多人喜欢用纸而非电脑的键盘,不能单单理解为一 种怀旧情怀。就是因为单单通过显示器来读的话,印象肤浅,所以一边写一边读。这样的话相对容易读懂代码。不是很好的名字要替换,晦涩难懂的深略语不单只记 录下来,也可替换。

但是,一定要将原来的程序备份以下,以免途中发现不合适时可以跟原来的程序对比一下。不这样的话,很容易被自己的一个小小失误而陷入困境。

替换后运行

跟前一项类似,只不过这里要将程序运行一下看看。比如,对动作很难理解的部分改变一下参数或程序试着运行一下。这样的话从运行的变化中可以推测出代码的意思。

还有就是,应该与原来的代码的运行情况作一下对比。

 

名字的重要性

写到这里好像程序的读解就是名字的调查。文件名,函数名,变量名,类型名,成员名等,似乎程序就是一堆名字。名字是程序的抽象化的最强大的武器,这可能是理所当然的,但当读程序的时候意思到这一点,能大大地提高效率。

 

读变更记录

程序一般都附有变更的记录这样的材料。比如GNU的软件必然有ChangeLog这个文件。这对理解程序这么变更的理由最有帮助。

还有,若使用了CVSSCCS这样的版本管理系统的话比起ChangeLog更具价值。以CVS为例,表示特定行的最后变更的cvs annotate,显示与指定版本差异的cvs diff等都很方便。

再者就是,开发时用到邮件组或新闻组时很容易对对过去的Log进行检索。记载了很多变更理由。当然也可以用Web检索。

动态解析工具

动态解析就是解析时使用调试器或对象监视器等。实际上代码是怎样的通路,怎样的数据构造等观测运行的程序的结果远比头脑的思考来的更快。可以使用以下的几款综合工具。

·         gdb

·         SourceNavigator

除此,使用printf来调试是比较原始的动态解析方法。

使用DDD (data display debugger)可以将数据结构变成图的形式。DDD通常作为各种调试器的UI,提供GUI的同时可以将很多东西可视化。比如http://www.gnu.org/software/ddd/all.jpg将链表可视化。

·         http://www.gnu.org/software/ddd/

一般,以文本的形式写出的话使用后述的graphviz来图形化为好。

针对函数的调用记录(Programm Trace)用ctrace这样的工具。Linux里有ltrace,笔者没有确定,Solaris里好像有同样的工具sotrace,可以记录共有库函数的调用。

特别是如果仅限于系统调用,有strace, ktrace, trussLinux的是straceBSD的是ktraceSolaris的是truss

ctrace

http://www.vicente.org/ctrace/

ltrace

http://packages.debian.org/unstable/utils/ltrace.html

strace

http://www.liacs.nl/~wichert/strace/

ktrace (OS )

truss (OS )

而且,据说Trace不仅仅只输出为文本的形式,也可以可视化。详细情况以下这本书中有记载。

"Programming Languages" Ravi Sethi, Tom Stone; Addison-Wesley Pub Co; ISBN: 0201590654; 2nd edition (February 1996)
邦译:『编成语言的概念和构造』新装版、Ravi Sethi / Tom Stone
PearsonEducation2002

这个说法的记载是在p145 4.4驱动具有变为箱子的持续时间(?)的前后。驱动树这个名字是在动态调用图的话题中引入的。驱动树好像是activation tree的翻译。

 

静态解析工具

使用后感觉global是最通用的。与独自的形式相比,以HTML为输出用Web浏览器浏览是最方便不过的了。

gonzui

http://gonzui.sourceforge.net/

    对应多种语言的代码搜索引擎。可以进行文件内的增量式检索及浏览代码。

global

http://www.gnu.org/software/global/

    C语言用。具有相互关联及函数的定义等的检索等高性能。与htags一起使用可以输出HTML不足的地方:不能显示全局变量及函数指针的定义。并且在使用htags生成HTML时虽然在Tag内可以增加属性值,直接输出Tag而不能用CSS来指定。我使用的是经过改造的。只是改变一下定义的全局字符串常量即可。(但是,要决定CSS名)

    可以包括在宏中定义的函数或全局变量,虽然不错,但一旦这样做就像C编译器一样需要解析。

cscope

http://cscope.sourceforge.net/

    用于C/C++/Java。基于Curses的代码浏览器。因为使用独自的命令而使用起来很不方便。没怎么使用过,但功能很多。很多人认为cscopeglobal毫不逊色。

ctags

http://ctags.sourceforge.net/

    基本上用于C语言。可以生成viTag文件。Tag文件就是可以记录函数或变量的位置并进行一系列跳转的日志。就像Emacs中使用的etags一样。

lxr

http://lxr.sourceforge.net/

Linux代码而开发的辅助工具。名字由Linux Cross Referencer而来。作为形式为CGI。因为比较喜欢独立工具,没怎么使用过这款。听说很方便使用。

doxygen

http://www.stack.nl/~dimitri/doxygen/

文档生成工具。注释可以写到文档里也可抽取出来,可以以多种格式输出。可以将代码以HTML等格式输出,功能很强大。但是代码HTML化时设定略显复杂。

cxref

http://www.gedanken.demon.co.uk/cxref/

C cross referencing & Documentation tool、即交叉参照,文档生成工具。若不添加注释就不能生成文档。基本上是一款文档生成工具,交叉参照只是附带功能。如果用于代码阅读可以使用任意一种功能。

cflow

http://wh58-508.st.uni-magdeburg.de/sparemint/html/packages/cflow.html

以前是UNIX附带的工具。可以把C语言函数的调用关系文档化。现在看来虽然不是特别方便,但很简单,也可输出到管道,也较实用。

另外告诉大家一个Fortran用的静态解析工具,以下是它的连接。

http://www.fortranlib.com/freesoft.htm#Static Analysis Tools

杂谈:关于调用关系的可视化

调用关系可视化的工具比较少,简单介绍一下当前情况。

SXT

http://sxt.freeservers.com/

单元内的函数的关系视觉化。对应语言为CdBASEFortranJavaLisp。是笔者最想找的工具。

VCG

http://rw4.cs.uni-sb.de/users/sander/html/gsvcg1.html

输入简单的记述语言后可以将其可视化。最近的cflowbison可以直接生成面向VCG的语言。可以实现函数,结构体,规则的关系的全自动化。

graphviz

http://www.research.att.com/sw/tools/graphviz/

输入dot形式的图形表示语言的信息,可以输出各种形式的图形。(PostScript, png, jpeg等等)

       下图是它的一个测试例子。Ruby解释器的中心。

本文的以前版本对调用关系可视化的内容的记述偏多。调用关系的视觉化很容易理解代码一系列的动作,但未必就一定管用。函数数目多,调用深度较深的时候可视化更能发挥它的作用。否则,也没有太多的必要。

 

译者注:

1.由于水平有限且时间仓促翻译错误在所难免,遇到读不懂之处敬请联系。

2.这里的静态解析与动态解析与基于编成规约的对代码的静态分析及对程序运行时的内存使用状况分析等的动态分析有概念,目的等的差别。这里侧重阅读与理解代码。

3.这里介绍的方法有可借鉴之处,即思想部分,对其中的一些工具,因为使用起来可能造成大家时间上的浪费,尤其是一些工具比较老,不一定很有价值。再者,这方面的工具种类繁多,理解了文章的思想足矣。

望这篇译文能对大家有所启发和帮助。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: QGroundControl(简称QGC)是一款开源的无人机地面站软件,用于控制和监控无人机的飞行。在实现飞行控制功能之前,需要对QGroundControl的代码进行解析。 首先,QGroundControl的代码主要由C++语言编写。代码解析的第一步是了解软件的整体架构。QGC主要包括几个核心模块,包括UI界面、数据处理和飞行控制等模块。其中,UI界面负责显示和交互,数据处理负责接收和处理来自无人机的数据,飞行控制模块负责实现飞行控制算法和指令下发等功能。 在代码解析过程中,需要关注的核心模块是飞行控制模块。该模块主要实现无人机的飞行控制算法,包括航向控制、高度控制、速度控制等。这些算法的实现是基于实时接收的传感器数据和用户设定的飞行任务参数进行计算。 此外,QGC还提供了一些实用工具,如地图显示、航点规划和飞行日志分析等功能。这些工具的实现依赖于基础库和第三方库的支持。 对于代码解析的进一步工作可以包括以下几个方面:深入了解QGC的代码结构和各个模块之间的关系,学习和理解飞行控制算法的实现细节,掌握软件的各种功能和使用方法,以及扩展功能的开发和定制等。 总结来说,QGroundControl的代码解析是一个深入了解并学习软件的过程。需要对软件的整体架构、核心模块和功能进行分析和理解,以便能够更好地进行开发和定制。 ### 回答2: QGroundControl是一个用于无人机和自动驾驶车辆控制的开源软件。它是一个功能强大且易于使用的地面站,提供了许多工具和功能来帮助用户控制和监视无人机和自动驾驶车辆的飞行和导航。 QGroundControl的代码解析主要涉及以下几个方面: 1. 界面和用户交互:QGroundControl的用户界面可以显示无人机和自动驾驶车辆的实时数据,如GPS位置、飞行高度、传感器数据等。代码解析中会涉及界面布局、控件创建和事件处理等技术。 2. 通信和数据处理:QGroundControl通过与无人机和自动驾驶车辆的通信接口来接收和发送数据。代码解析中会涉及串口通信、数据解析和处理、命令下发等方面的代码。 3. 地图和导航:QGroundControl可以显示地图,并通过地图辅助用户进行飞行和导航。代码解析中会涉及地图API的使用、位置解算、航迹规划等相关代码。 4. 参数配置和设置:QGroundControl可以通过界面配置和设置无人机和自动驾驶车辆的参数。代码解析中会涉及参数读写、验证和保存等方面的代码。 5. 模块化设计和拓展性:QGroundControl的代码采用了模块化设计,方便用户进行功能拓展和定制。代码解析中会涉及模块的划分、接口设计和扩展点的使用等方面的代码。 总之,QGroundControl的代码解析涵盖了界面、通信、地图、导航、参数配置和模块化设计等多个方面。通过深入分析代码,可以进一步理解QGroundControl的工作原理和内部实现,为用户提供更好的飞行和导航控制体验。 ### 回答3: QGroundControl是一个开源的地面站软件,用于飞行控制系统的控制和监控。其代码解析主要涉及到源代码的结构和各个模块的功能。 QGroundControl的代码主要由C++和Qt库实现。其整体结构清晰,分为主要的四个部分:固件、地面站、共享库和API。 固件包含了无人机的飞行控制固件代码,主要功能是读取传感器数据,计算飞行控制指令并发送给飞行控制器。地面站是指QGroundControl软件本身,它提供了用于监控和控制无人机的用户界面,包括飞行参数设置、飞行任务规划、实时数据显示等。 共享库是一些可以被固件和地面站共同使用的功能模块,提供了一些通用的功能,如地理信息处理、飞行轨迹规划、无线通信等。这些共享库的代码可以在固件和地面站中重复使用,提高了代码的可复用性。 API是QGroundControl的应用程序接口,提供了一些可以被其他应用程序调用的功能,如地图显示、航点设置、数据记录等。开发人员可以利用API扩展QGroundControl的功能,或将其集成到其他系统中。 QGroundControl代码解析需要对C++和Qt库有一定的了解。可以通过阅读源代码、注释和文档来理解各个模块的功能和实现原理。在解析代码时,可以重点关注与飞行控制、用户界面和通信相关的模块,对关键功能进行详细分析和调试,以深入理解代码的实现细节和逻辑。 总之,QGroundControl代码解析是一个对代码结构和功能进行深入理解和分析的过程,通过研究源代码和文档,开发人员可以更好地理解QGroundControl的工作原理,并进行二次开发和定制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值