如何读懂c++源码?

六个章节:

( 1 )读懂程序码,使心法皆为我所用。
( 2 )摸清架构,便可轻松掌握全貌。
( 3 )优质工具在手,读懂程序非难事。
( 4 )望文生义,进而推敲组件的作用。
( 5 )找到程序入口,再由上而下抽丝剥茧。
( 6 )阅读的乐趣,透过程序码认识作者。

阅读他人的程序码( 1 ) ---读懂程序码,使心法皆为我所用
程序码是别人写的,只有原作者才真的了解程序码的用途及涵义。许多程序人心里都有一种不自觉的恐惧感,深怕被迫去碰触其他人所写的程序码。但是,与其抗拒接收别人的程序码,不如彻底了解相关的语言和惯例,当成是培养自我实力的基石。
对大多数的程序人来说,撰写程序码或许是令人开心的一件事情,但我相信,有更多人视阅读他人所写成的程序码为畏途。许多人宁可自己重新写过一遍程序码,也不愿意接收别人的程序码,进而修正错误,维护它们,甚至加强功能。

这其中的关键究竟在何处呢?若是一语道破,其实也很简单,程序码是别人写的,只有原作者才真的了解程序码的用途及涵义。许多程序人心里都有一种不自觉的恐惧感,深怕被迫去碰触其他人所写的程序码。这是来自于人类内心深处对于陌生事物的原始恐惧。

读懂别人写的程序码,让你收获满满
不过,基于许多现实的原因,程序人时常受迫要去接收别人的程序码。例如,同事离职了,必须接手他遗留下来的工作,也有可能你是刚进部门的菜鸟,而同事经验值够了,升级了,风水轮流转,一代菜鸟换菜鸟。甚至,你的公司所承接的专案,必须接手或是整合客户前一个厂商所遗留下来的系统,你们手上只有那套系统的原始码(运气好时,还有数量不等的文件)。

诸如此类的故事,其实时常在程序人身边或身上持续上演着。许多程序人都将接手他人的程序码,当做一件悲惨的事情。每个人都不想接手别人所撰写的程序码,因为不想花时间去探索,宁可将生产力花在产生新的程序码,而不是耗费在了解这些程序码上。

先了解系统架构与行为模式,再细读
倘若撰写程序码是程序人的重要技艺之一,那么读懂别人的程序码,接着加以修改,也势必是另一个重要的技艺。

如果你不能熟悉这项工作,不仅在遭逢你所不愿面对的局面时,无法解决眼前接手他人程序码的难题,更重要的是,当你看着眼前现成的程序码,却不知如何从中撷取自己所需,导致最后只能入宝山空手回,望之兴叹。

接触他人的程序码,大致上可以分为三种程度:一,了解,二,修改,扩充,三,抽取,提炼。了解别人的程序码是最基础的工作,倘若不能了解自己要处理的程序码,就甭论修改或扩充,更不可能去芜存菁,从中萃取出自己所需,回收再利用别人所撰写的程序码。虽说是“阅读” ,但程序码并不像文章或小说一样,透过这种做法,便能够获得一定程度的了解。阅读文章或小说时,几乎都是循序地阅读,你只消翻开第一页,一行行阅读下去即可。但是,有许多程序人在试着阅读其他人的程序码时,却往往有不知如何读起的困难。

或许找到系统的第一页(也就是程序码执行的启始点)并不难,但是复杂度高的系统,有时十分庞大,有时千头万绪。

从程序码的启始点开始读起,一来要循序读完所有的程序码旷日费时,二来透过这种方式来了解系统,很难在脑中构建出系统的面貌,进而了解到系统真正的行为。所以,阅读程序码的重点,不在于读完每一行程序码,而是在于有效率地透过探索及阅读,从而了解系统的架构及行为模式。以便在你需要了解任何片段的细节实作时,能够很快在脑上对映到具体的程序码位置,直到那一刻,才是细读的时机。

熟悉沟通语言与惯例用语
不论如何,有些基本的准备,是阅读他人程序码时必须要有的。

首先,你最好得了解程序码写成的程序语言。想要读懂法文写成的小说,总不能连法文都不懂吧。有些情况则很特殊。我们虽然不懂该程序码撰写所用的语言,但是因为现代语言的高阶化,而且流行的程序语言多半都是血统相近,所以即使不那么熟悉,有时也可勉力为之。

除了认识所用语言之外,再来就是要先确认程序码所用的命名惯例(命名惯例)。了解命名惯例很重要,不同的程序人或开发团队,差异可能很大。
这命名惯例涵盖的范围通常包括了变数的名称,函式的名称,类别(如果是物件导向的话)的名称,原始码档案,甚至是专案建构目录的名称。倘若使用了像设计模式之类的方法,这些名称更有一些具体的表述方式。

命名惯例有点像是程序人在程序语言之上,另行建构的一组沟通行话。程序人会透过共通约束,遵守的命名惯例,来表达一些较高阶的概念。例如,有名的匈牙利式命名法,便将变数名称以属性,型别,说明合并在一起描述。对程序人来说,这种方式能够提供更丰富的资讯,以了解该变数的作用及性质。

对程序码阅读来说,熟悉这个做法之所以重要,是因为当你了解整个系统所采用的惯例时,你便能试着以他们所共同操用的语汇来进行理解。倘若,不能了解其所用的惯例,那么这些额外提供的资讯,就无法为你所用。像以设计模式写成的程序码,同样处处充满着模式的名称,诸如:工厂,门面,代理等等。以这些名称指涉的类别,也直接透过名称,表达了它们自身的作用。对于懂得这命名惯例的读者来说,不需要深入探索,也能很快捕捉到这些类别的意义。

当你拿到一套必须阅读的程序码时,最好先取得命名惯例的说明文件。然而,并不是每套程序码都附有此类的说明文件。另一个方式,就是自己到程序码中,大略浏览一遍,有经验的程序人可以轻易发掘出该系统所用的命名惯例。

常见的命名方式不脱那几类,这时候经验就很重要,倘若你知道的惯例越多,就越能轻易识别他人所用的惯例。如果运气很糟,程序码所用的惯例是前所未见的,那么你也得花点时间归纳,凭自己的力量找出这程序码命名上的规则。

掌握程序码撰写者的心态与习惯
大多数的程序码,基本上都依循一致的命名惯例。不过运气更差的时候,一套系统中可能会充斥着多套命名惯例。这有可能是因为开发团队由多组人马所构成,每组人马都有不同的文化,而在专案开发管理又没有管控得宜所造成。最糟的情况,程序码完全没有明显的惯例可言,这时候阅读的难度就更高了。

想要阅读程序码,得先试着体会程序码作者的“心” 。想要这么做,就得多了解对方所使用的语言,以及惯常运用的语汇。在下一回中,我们将继续探讨阅读程序码的相关议题。
阅读他人的程序码( 2 ) -摸清架构,便可轻松掌握全貌
在本文中,我们的重点放在:要了解一个系统,最好是采取由上至下的方式。先试着捕捉系统架构性的观念,不要过早钻进细节,因为那通常对于你了解全貌,没有多大的帮助。阅读程序码不需要从第一行读起,我们的目的并不是在于读遍每一段程序码。
基于许多原因,程序人需要阅读其他人所写成的程序码。而对程序设计2.0时代的程序人来说,最正面的价值在于,能读懂别人程序的人,才有能力从中萃取自己所需的程序,借以提高生产力。

阅读程序码的目的,在于了解全貌而非细节
想要读懂别人程序码的根本基础,便是了解对方所用的程序语言及命名惯例。有了这个基础之后,才算是具备了基本的阅读能力。正如我之前提到的─ ─想要读懂法文写成的小说,总不能连法文都不懂吧。阅读程序码和阅读文学作品,都需要了解撰写所用的语言及作者习用的语汇。

但我们在阅读文学作品通常是采循序的方式,也就是从第一页开始,一行一行地读下去,依循作者为你铺陈的步调,逐渐进到他为你准备好的世界里。阅读程序码却大大不同。我们很少从第一行开始读起,因为除非它是很简单的单执行绪程序,否则很少这么做。因为要是这么做,就很难了解整个系统的全貌。是的,我们这边提到了一个重点,阅读程序码的目的在于了解系统的全貌,而不是在于只是为了地毯式的读遍每一段程序码。

就拿物件导向程序语言所写成的系统来说,整个系统被拆解,分析成为一个个独立的类别。阅读个别类别的程序码,或许可以明白每项类别物件个别的行为。但对于各类别物件之间如何交互影响,如何协同工作,又很容易陷入盲人摸象的困境。这是因为各类别的程序码,只描述个别物件的行为,而片段的阅读就只能造就片面的认识。

由上而下厘清架构后,便可轻易理解组成关系
如果你想要跳脱困境,不想浪费大量时间阅读程序码,却始终只能捕捉到对系统片段认识,就必须转换到另一种观点来看待系统。从个别的类别行为着手,是由下至上(自下而上)的方法;在阅读程序码时,却应该先采由上至下(自上而下)的方式。对程序码的阅读来说,由上至下意谓着,你得先了解整个系统架构。

系统的架构是整个系统的骨干,支柱。它表现出系统最突出的特征。知道系统架构究竟属于那一种类型,通常大大有益于了解系统的个别组成之间的静态及动态关系。有些系统因为所用的技术或框架的关系,决定了最上层的架构。例如,采用的Java Servlet的/ JSP的技术的应用系统,最外层的架构便是以J2EE的(或起码的J2EE中的Web容器)为根本。

使用的Java Servlet的/ JSP的技术时,决定了某些组成之间的关系。例如, Web容器依据web.xml中的内容载入所有的Servlets ,听众,以及过滤器。每当语境发生事件(例如初始化)时,它便会通知监听类别。每当它收到来自客户端的请求时,便会依循设定的所有过滤器链,让每个过滤器都有机会检查并处理此一请求,最后再将请求导至用来处理该请求的Servlet的。

当我们明白某个系统采用这样的架构时,便可以很容易地知道各个组成之间的关系。即使我们还不知道究竟有多少Servlets ,但我们会知道,每当收到一个请求时,总是会有个相对应的服务器来处理它。当想要关注某个请求如何处理时,我应该去找出这个请求对应的服务器。

了解架构,必须要加上层次感
同样的,以爪哇写成的网页应用程序中,也许会应用诸如Struts的之类的的MVC框架,以及像Hibernate的这样的资料存取框架。它们都可以视为最主要的架构下的较次级架构。而各个应用系统,甚至有可能在Struts的及休眠之下,建立自有的更次级的架构。

时间: 2024-10-14 04:11:03

如何读懂c++源码?的相关文章

读Unsafe类源码

Unsafe类简介 JUC中很多的实现都是调用了Unsafe类来实现的,所以这里阅读下该类的内容. Unsafe类包装了很多低级别的非安全性操作.虽然该类及其所有的方法都是public的,但是它只能被受信任的代码使用(也就是jdk中的代码) 读源码过程中,这里只会对部分方法进行说明,其余的方法要么类似要么不那么重要. 读源码 //构造方法私有化 private Unsafe() {} //采用饿汉式单例 private static final Unsafe theUnsafe = new Un

深入理解读写锁—ReadWriteLock源码分析

ReadWriteLock管理一组锁,一个是只读的锁,一个是写锁.读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的. 所有读写锁的实现必须确保写操作对读操作的内存影响.换句话说,一个获得了读锁的线程必须能看到前一个释放的写锁所更新的内容. 读写锁比互斥锁允许对于共享数据更大程度的并发.每次只能有一个写线程,但是同时可以有多个线程并发地读数据.ReadWriteLock适用于读多写少的并发情况. Java并发包中ReadWriteLock是一个接口,主要有两个方法,如下: public i

读Hadoop3.2源码,深入了解java调用HDFS的常用操作和HDFS原理

本文将通过一个演示工程来快速上手java调用HDFS的常见操作.接下来以创建文件为例,通过阅读HDFS的源码,一步步展开HDFS相关原理.理论知识的说明. 说明:本文档基于最新版本Hadoop3.2.1 目录 一.java调用HDFS的常见操作 1.1.演示环境搭建 1.2.操作HDFS 1.3.java文件操作常用方法 二.深入了解HDFS写文件的流程和HDFS原理 2.1.Hadoop3.2.1 源码下载及介绍 2.2.文件系统:FileSystem 2.3.HDFS体系结构:namenod

读AbstractQueuedSynchronizer类源码

感受 这个类的代码除去注释差不多有千多行,要想把所有代码都读完,然后按照作者的思路给理解完,是不容易的.这里我仔仔细细读了差不多一半的代码,说难倒不是很难. 虽然没有完全看完,但是基本上理解了作者代码的意图..说得简单些,就是操作一个双向链表.而链表中的每个节点有多种状态.AQS就是要保证整个双向链表和节点的状态的正确性. 连续看了好几天的JUC相关的源码,现在脑袋真有点晕乎乎的.加上这个类的代码确实有点多,这个就不在整理这个类的分析结果,就直接把代码copy了,并附上一张图.(这里只贴出分析过

<转>如何高效快速看懂Android源码

原网址:http://jingyan.baidu.com/article/574c5219ca78ed6c8d9dc12a.html 在Android系统上工作了一段时间,经常会遇到题目中的问题,下面说说我的看法: 1.需要先找一个开头,和UI有直接关系的就是最常见的Activity了吧,我就从它开始解剖.从Activity的创建入手,寻找Activity真正的创建位置,setContentview这个方法很明显和UI有关,这两方面一结合,我发现了ViewRoot和WindowManager的身

试试看读一下Zepto源码

在浏览器上(Safari.Chrome和Firefox)上开发页面应用或者构建基于html的web-view本地应用,你如PhoneGap,使用Zepto是一个不错的选择. Jquery和Zepto的区别 由于我原先并没有用过Zepto,所以首先试了一下Jquery和Zepto的区别 1:$(function(){});       J,Z通用,页面加载完毕执行回调函数(Zepto中的$—>Zepto),当然都是可以省略的 源码看不懂的地方汇总 1:从this === void 0说起 二.为什

读《Spring 源码深度解析》随记

bean 是Spring 中最核心的东西,因为Spring就像是个大水桶,而bean就像是容器中的水,水桶脱离了水便也没什么用处了. 一.核心类: 1.DefaultListableBeanFactory XmlBeanFactory 继承自 DefaultListableBeanFactory ,而 DefaultListableBeanFactory 是整个bean加载的核心部分,是 spring 注册及加载 bean 的默认实现,而对于 XmlBeanFactory 与 DefaultLi

读《Spring源码深度解析》总结1-全篇介绍

读android系统源码情景分析笔记(一)

android2.3系统驱动模块由内核模块,硬件抽象模块,用户调用模块(jni)组成,内核模块和linux一致,硬件抽象模块主要需要定义两个结构:hw_module_t和hw_device_t. hw_module_t包含模块id,版本号,署名和一个函数指针: int open (struct hw_module_t* module, const char* id, struct hw_device_t** device); hw_device_t包含版本,hw_module_t的引用和一个函数