如何阅读一份源代码?_如何阅读一套战斗系统的源码-程序员宅基地

技术标签: 方法论  数据结构  

先跑起来

精简环境。

调试手段

断点调试。并不是所有项目代码,跑起来之后都自带调试信息能够断点调试的。所以在自己的调试环境里需要先确定这一点。比如一些C相关的项目,基本都是”./configure & make”来编译,但是makefile中的编译flags使用了O2之类的优化选项,此时需要自己先手动修改成”-O0 -g”,即编译生成的二进制中不优化且带上调试信息。

使用顺手的工具

好的工具会让你事半功倍,这一点应该很多人都同意。

我阅读Go代码的时候,喜欢使用IDEA,这个IDE工具可以完美的做到以下几点:

符号的定位、跳转、查找符号被引用的地方。
左边能够展开一个源码文件中的所有符号。
反之,很多人推崇的VSCode,我几次尝试使用用来阅读GoC类代码,都觉得不够顺手,查找符号能力不行、也没有地方可以看到一个文件中出现的符号。

C\C++类的代码,在尝试各种工具之后,还是使用Vim+Ctags+Cscope来写CC++代码。

情景分析

假如有了前面的基础,已经能够让项目顺利在自己的调试环境跑起来了,那么就可以对项目代码进行情景分析了。

所谓的“情景分析”,我的理解就是自己构造一些情景,然后通过加断点、调试语句等分析在这些场景下的行为。

以我自己为例,在写《Lua设计与实现》时,讲解到Lua虚拟机指令的解释和执行过程中,需要针对每个指令做分析,此时用的就是情景分析的方法。我会模拟出来使用该指令的Lua脚本代码,然后在程序里断点调试这些场景下的行为。

我惯用的做法,是在某个重要的入口函数上面加上断点,然后构造触发场景的调试代码,当代码在断点处停下,通过查看堆栈、变量值等等来观察代码的行为。

例如,Lua解释器代码中中,生成Opcode最终都会调用函数luaK_code,那么我就在这个函数上面加上断点,然后构造我想要调试的场景,只要在断点处中断,我通过函数堆栈就能看到完整的调用流程:

情景分析的好处在于:不会在一个项目中大海捞针似的查找,而是能够把问题缩小到一个范围内展开来理解。

“情景分析”这一概念不是我想出来的名词,比如有这么几本分析代码的书籍,如:《Linux内核源代码情景分析》,《Windows内核情景分析》。

利用好测试用例

好的项目都会自带不少用例,这类型的例子有:etcdgoogle出品的几个开源项目。

如果测试用例写的很仔细,那么很值得好好去研究一下。原因在于:测试用例往往是针对某个单一的场景,独自构造出一些数据来对程序的流程进行验证。所以,其实跟前面的“情景分析”一样,都是让你从大的项目转而关注具体某个场景的手段之一。

厘清核心数据结构之间的关系

虽然说“程序设计=算法+数据结构”,然后我实际中的体会,数据结构更加重要。

因为结构定义了一个程序的架构,结构定下来了才有具体的实现。

因此,在阅读一份代码时,厘清核心的数据结构之间的关系尤其重要。这个时候,需要使用一些工具来画一下这些结构之间的关系,我的源码分析类博客中有很多这样的例子,比如《Leveldb代码阅读笔记》、《Etcd存储的实现》等等。

需要说明的是,情景分析、厘清核心数据结构这两步并没有严格的顺序关系,不见得是先做某事再做某事,而是交互进行的。

比如,你如果现在刚接手某个项目,需要简单的了解一下项目,可以先阅读代码了解都有哪些核心数据结构。理解了之后,如果不清楚某些情景下的流程,可以使用情景分析法。总而言之,交替进行直到解答你的疑问为止。

整体和细节

阅读代码的过程中,需要在整体和细节之间做权衡。

比如,有时候你需要大体了解一个整体的框架、轮廓、流程之后,才能再针对具体的细节深入进去。这个时候,不宜针对具体的函数实现、算法等深入分析。而细节的分析,又不能缺少,否则一些东西的理解又流于表面。

所以,如何把握整体和细节是一个需要累积阅读代码经验才能把握好的。我的建议是:过程中还是以整体为首,在不理解整体的前提之前,不要太过深入某个细节。把某个函数、数据结构当成一个黑盒,知道它们的输入、输出就好,只要不影响整体的理解就暂且放下接着往前看。

多问自己几个问题

输出的手段有很多,在阅读代码时,比较建议的是自己能够多问自己一些问题,比如:

为什么选择这个数据结构来描述这个问题?类似的场景下,其他项目是怎么设计的?都有哪些数据结构做这样的事情?
如果由我来设计这样的项目,我会怎么做?
等等等等。越是主动积极的思考,就越有更好的输出,输出质量与学习质量成正比关系。

写自己的代码阅读笔记

我从开始写博客,就是写不少各种项目的代码解读类文章,网名“codedump”也源于想把“code内部的实现原理dump出来”之意。

前面提到学习质量与输出质量成正比关系,这是我自己的深刻体会。也因为如此,所以才要坚持阅读源码之后写自己的分析类笔记。

写这类笔记,有以下几个需要注意的地方。

虽然是笔记,但是要想象着在向一个不太熟悉这个项目的人讲解原理,或者想象一下是几个月甚至几年后的自己回头来看这个文章。在这种情况下,会尽量的把语言组织好,循循善诱的解释。

尽量避免大段的贴代码。我认为在这类文章中,大段贴上代码有点自欺欺人:就是看上去自己懂了,其实并不见得。如果真要解释某段代码,可以使用伪代码或者缩减代码的方式。记住:不要自欺欺人,要真的懂了。如果真的想在代码上加上自己的注释,我有一个建议是fork出来一份该项目某个版本的代码,提交到自己的github上,上面随时可以加上自己的注释并且保存提交。比如我自己注释的etcd 3.1.10代码:etcd-3.1.10-codedump,类似的我阅读的其他项目都会在githubfork出一个带上codedump后缀的项目。

多画图,一图胜千言,使用图形展示代码流程、数据结构之间的关系。我最近才发现画图能力也是很重要的能力,自己在从头学习如何使用图像来表达自己的想法。

写作是很重要的基础能力,我一个朋友最近教育我,大体的意思是说:如果你在某方面的能力很强,如果再加上写作好、英语好,那么将极大放大你在这方面的能力。而类似写作、英语这样的底层基础能力,不是一撮而就的,需要长时间保持练习才可以。而写博客,对于技术人员而言,就是一种很好的锻炼写作的手段。

总结

以上是我简单总结的一些阅读源码时候的手段和注意方法,大体而言有那么几点吧:

只有更好的输出才能更好的消化知识,所谓的搭建调试环境、情景分析、多问自己问题、写代码阅读笔记等都是围绕输出来展开的。总而言之,不能像一条死鱼一样指望着光靠看代码就能完全理解它的原理,需要想办法跟它互动起来。
写作是人的基础硬实力之一,不仅锻炼自己表达能力,还能帮助整理自己的思路。对程序员而言锻炼写作能力的手段之一就是写博客,越早开始锻炼越好。
最后,如同任何可以习得的技能一般,阅读代码这种能力也需要长时间、大量的反复练习,下一次就从自己感兴趣的项目开始锻炼自己的这种技能吧。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/sunshineywz/article/details/104277664

智能推荐

C语言 | windows命令行编译(Cygwin)_cygwin编译命令-程序员宅基地

文章浏览阅读2.2k次。本文更好的排版方式:https://mp.weixin.qq.com/s?__biz=MzU5MzcyMjI4MA==&mid=100000740&idx=1&sn=f2b589c6930bb6576b5f59997dbef111&chksm=7e0d6d23497ae43532bc906510246c23a885_cygwin编译命令

IMX6ULL系列学习记录-sii902x移植篇-程序员宅基地

文章浏览阅读4.7k次,点赞5次,收藏19次。主题:IX6ULL sii902x移植记录(参考官方文档Sii9022a HDMI transmitter driver)硬件平台:野火IMX6ULL软件:ubuntu19.04交叉编译器:gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihfU-Boot:uboot-imx-rel_imx_4.1.15_2.1.0_gaker..._sii902x

跟着官方文档学DGL框架第十天——训练图神经网络之链接预测_链接预测 图神经网络-程序员宅基地

文章浏览阅读6.4k次,点赞14次,收藏65次。参考链接https://docs.dgl.ai/en/latest/guide/training-link.html#guide-training-link-prediction概述什么是链接预测链接预测就是预测图中给定节点间是否存在边,常用于推荐系统。形式化地,给定节点uuu和vvv,链接预测的任务就是得到它们间存在链接的概率yu,v=ϕ(u,v)y_{u,v}=\phi \left ( u,v\right )yu,v​=ϕ(u,v)。具体到GNN上,我们通过L层的GNN得到节点uuu和vv_链接预测 图神经网络

nginx和uwsgi的配置以及uwsgi日志文件的切割和过期日志的删除_uwsgi.log可以删除吗-程序员宅基地

文章浏览阅读2.7k次。nginx配置文件worker_processes 4;events { worker_connections 1024;}http { include /home/nginx/conf/mime.types; default_type application/octet-stream; log_format ..._uwsgi.log可以删除吗

【渗透技巧】pop3协议渗透_pop3渗透-程序员宅基地

文章浏览阅读6.1k次,点赞3次,收藏15次。【渗透技巧】pop3协议渗透banner信息获取nmap pop3脚本扫描pop3爆破pop命令行命令行登录pop邮箱telnet方式nc方式例子banner信息获取nc -nv <IP> 110nmap pop3脚本扫描nmap --scripts "pop3-capabilities or pop3-ntlm-info" -sV -port <PORT> <IP> pop3爆破可以使用hydra或者xhydra。hydra-wizard可以提供命令行向_pop3渗透

【ICPC济南区域赛】签到题题解_icpc2021济南题解-程序员宅基地

文章浏览阅读406次。M Cook Pancakes!对于N个饼,显然需要fry 2N次;考虑最优的情况,显然在每次都同时fry K次即答案为 【2N/K】#include<bits/stdc++.h>using namespace std; int main(){ int N,K; cin>>N>>K; if(N<=K)cout<<2<<endl; else{ cout<<ceil(2_icpc2021济南题解

随便推点

如何升级Carbide C++的GCCE Tool Chain_no tool chain set up in kit "desktop qt 5.9.6 gcc -程序员宅基地

文章浏览阅读2.4k次。Carbide C++的编译器在Symbian开发工程中,Carbide C++是非常好用的开发工具,目前提供GCCE,ARMV5和RVCT三种编译器的支持。前两种编译器是免费的,RVCT是收费的编译工具,网上下载的Carbide并不默认提供,需要自己下载并配置才能使用,由于RVCT提供了专门的优化,编译结果的目标文件体积很小,且代码执行效率更高,但问题是该编译器费用比较昂贵,普通开发_no tool chain set up in kit "desktop qt 5.9.6 gcc 64bit" for "c++".

断点续传、大文件上传、秒传、webuploader_webuploader 限制视频文件上传的秒数-程序员宅基地

文章浏览阅读317次。一、 功能性需求与非功能性需求 要求操作便利,一次选择多个文件进行上传;支持大文件上传(1G),同时需要保证上传期间用户电脑不出现卡死等体验;交互友好,能够及时反馈上传的进度;服务端的安全性,不因上传文件功能导致JVM内存溢出影响其他功能使用;最大限度利用网络上行带宽,提高上传速度;二、 设计分析 对于大文件的处理,无论是用户端还是服务端,如果一次性进行读取发送、接收都是..._webuploader 限制视频文件上传的秒数

gRPC学习之五:gRPC-Gateway实战,java分层架构_grpc gateway java-程序员宅基地

文章浏览阅读803次。GO的gRPC开发环境准备极速搭建gRPC-Gateway环境所谓的搭建gRPC-Gateway环境,其实是完成以下三件事:在搭建环境时参考了一些网上的文章,结果遇到了各种问题一直没有成功(我当然不会认为文章有问题,必须认识到是自己能力不足的原因所致);经过反复折腾后终于成功后,我把所有操作做成一个shell脚本,执行以下命令即可完成上图中的所有操作:curl -o install-grpc-gateway.sh \https://raw.githubusercontent._grpc gateway java

利用githubpage和codingpage创建个人主页_coding 实现 github.io 个人主页-程序员宅基地

文章浏览阅读1.9k次。github page 创建个人主页使用帮助:https://pages.github.com/我的主页:http://mouday.github.io/当然,我绑定了自己的域名:https://www.pengshiyu.com/至于域名前面的绿锁头可以参考: 给自己github绑定的域名加个绿锁头httpscoding page创建个人主页使用帮助:https..._coding 实现 github.io 个人主页

存储过程 @与字符连接_存储过程连接符-程序员宅基地

文章浏览阅读289次。&gt; BEGIN -&gt; declare a int; -&gt; declare b varchar(5000); -&gt; set a=1; -&gt; set b=''; -&gt; while a&lt;10 do -&gt; set b = concat(b,',',a); -&gt; set a=a+_存储过程连接符

实验三 顺序图、协作图设计_添加课程顺序图-程序员宅基地

文章浏览阅读6.1k次,点赞6次,收藏36次。实验三 顺序图、协作图设计【实验目的】理解顺序图和协作图的概念及作用; 掌握UML顺序图与协作图的基本图形,了解它们各自的组成元素、特定作用和适用场合; 重点掌握顺序图的画法及其中元素所代表的意义。【实验性质】设计性实验。【实验要求】学习根据指定的用例描述绘制顺序图和协作图的方法; 学习使用Rational Rose绘制顺序图和协作图; 掌握顺序图和协作图的相互转换方法。【实验内容】以网上选课系统中的Select Course(选课)用例为例,设计和实现顺序图、协作图.._添加课程顺序图