搜档网
当前位置:搜档网 › 如何阅读别人代码

如何阅读别人代码

如何阅读别人代码
如何阅读别人代码

如何阅读别人代码

code reading

++++++++++++

第一章: 导论

++++++++++++

1.要养成一个习惯, 经常花时间阅读别人编写的高品质代码.

2.要有选择地阅读代码, 同时, 还要有自己的目标. 您是想学习新的模式|编码风格|还是满足某些需求的方法.

3.要注意并重视代码中特殊的非功能性需求, 这些需求也许会导致特殊的实现风格.

4.在现有的代码上工作时, 请与作者和维护人员进行必要的协调, 以避免重复劳动或产生厌恶情绪.

5.请将从开放源码软件中得到的益处看作是一项贷款, 尽可能地寻找各种方式来回报开放源码社团.

6.多数情况下, 如果您想要了解"别人会如何完成这个功能呢?", 除了阅读代码以外, 没有更好的方法.

7.在寻找bug时, 请从问题的表现形式到问题的根源来分析代码. 不要沿着不相关的路径(误入歧途).

8.我们要充分利用调试器|编译器给出的警告或输出的符号代码|系统调用跟踪器|数据库结构化查询语言的日志机制|包转储工具和Windows的消息侦查程序, 定出的bug的位置.

9.对于那些大型且组织良好的系统, 您只需要最低限度地了解它的全部功能, 就能够对它做出修改.

10.当向系统中增加新功能时, 首先的任务就是找到实现类似特性的代码, 将它作为待实现功能的模板.

11.从特性的功能描述到代码的实现, 可以按照字符串消息, 或使用关键词来搜索代码.

12.在移植代码或修改接口时, 您可以通过编译器直接定位出问题涉及的范围, 从而减少代码阅读的工作量.

13.进行重构时, 您从一个能够正常工作的系统开始做起, 希望确保结束时系统能

够正常工作. 一套恰当的测试用例(test case)可以帮助您满足此项约束.

14.阅读代码寻找重构机会时, 先从系统的构架开始, 然后逐步细化, 能够获得最大的效益.

15.代码的可重用性是一个很诱人, 但难以理解与分离, 可以试着寻找粒度更大一些的包, 甚至其他代码.

16.在复查软件系统时, 要注意, 系统是由很多部分组成的, 不仅仅只是执行语句. 还要注意分析以下内容: 文件和目录结构|生成和配置过程,用户界面和系统的文档.

18.可以将软件复查作为一个学习|讲授|援之以手和接受帮助的机会.

++++++++++++++++++++

第二章: 基本编程元素

++++++++++++++++++++

19.第一次分析一个程序时, main是一个好的起始点.

20.层叠if-else if-...-else序列可以看作是由互斥选择项组成的选择结构.

21.有时, 要想了解程序在某一方面的功能, 运行它可能比阅读源代码更为恰当.

22.在分析重要的程序时, 最好首先识别出重要的组成部分.

23.了解局部的命名约定, 利用它们来猜测变量和函数的功能用途.

24.当基于猜测修改代码时, 您应该设计能够验证最初假设的过程. 这个过程可能包括用编译器进行检查|引入断言|或者执行适当的测试用例.

25.理解了代码的某一部分, 可能帮助你理解余下的代码.

26.解决困难的代码要从容易的部分入手.

27.要养成遇到库元素就去阅读相关文档的习惯; 这将会增强您阅读和编写代码的能力.

28.代码阅读有许多可选择的策略: 自底向上和自顶向下的分析|应用试探法和检查注释和外部文档, 应该依据问题的需要尝试所有这些方法.

29.for (i=0; i

30.涉及两项不等测试(其中一项包括相等条件)的比较表达式可以看作是区间成员测试.

31.我们经常可以将表达式应用在样本数据上, 借以了解它的含义.

32.使用De Morgan法则简化复杂的逻辑表达式.

33.在阅读逻辑乘表达式时, 问题可以认为正在分析的表达式以左的表达式均为true; 在阅读逻辑和表达式时, 类似地, 可以认为正在分析的表达式以左的表达式均为false.

34.重新组织您控制的代码, 使之更为易读.

35.将使用条件运行符? :的表达式理解为if代码.

36.不需要为了效率, 牺牲代码的易读性.

37.高效的算法和特殊的优化确实有可能使得代码更为复杂, 从而更难理解, 但这并不意味着使代码更为紧凑和不易读会提高它的效率.

38.创造性的代码布局可以用来提高代码的易读性.

39.我们可以使用空格|临时变量和括号提高表达式的易读性.

40.在阅读您所控制的代码时, 要养成添加注释的习惯.

41.我们可以用好的缩进以及对变量名称的明智选择, 提高编写欠佳的程序的易读性.

42.用diff程序分析程序的修订历史时, 如果这段历史跨越了整体重新缩排, 常常可以通过指定-w选项, 让diff忽略空白差异, 避免由于更改了缩进层次而引入的噪音.

43.do循环的循环体至少执行一次.

44.执行算术运算时, 当b=2n-1时, 可以将a&b理解为a%(b+1).

45.将a<

46.将a>>n理解为a/k, k=2n.

47.每次只分析一个控制结构, 将它的内容看作是一个黑盒.

48.将每个控制结构的控制表达式看作是它所包含代码的断言.

49.return, goto, break和continue语句, 还有异常, 都会影响结构化的执行流程. 由于这些语句一般都会终止或重新开始正在进行的循环,因此要单独推理它们的行为.

50.用复杂循环的变式和不变式, 对循环进行推理.

51.使用保持含义不变的变换重新安排代码, 简化代码的推理工作.

+++++++++++++++++++

第三章: 高级C数据类型

+++++++++++++++++++

52.了解特定语言构造所服务的功能之后, 就能够更好地理解使用它们的代码.

53.识别并归类使用指针的理由.

54.在C程序中, 指针一般用来构造链式数据结构|动态分配的数据结构|实现引用调用|访问和迭代数据元素|传递数组参数|引用函数|作为其他值的别名|代表字符串|以及直接访问系统内存.

55.以引用传递的参数可以用来返回函数的结果, 或者避免参数复制带来的开销.

56.指向数组元素地址的指针, 可以访问位于特定索引位置的元素.

57.指向数组元素的指针和相应的数组索引, 作用在二者上的运算具有相同的语义.

58.使用全局或static局部变量的函数大多数情况都不可重入(reentrant).

59.字符指针不同于字符数组.

60.识别和归类应用结构或共用体的每种理由.

61.C语言中的结构将多个数据元素集合在一起, 使得它们可以作为一个整体来使用, 用来从函数中返回多个数据元素|构造链式数据结构|映射数据在硬件设备|网络链接和存储介质上的组织方式|实现抽象数据类型|以及以面向对象的方式编程.

62.共用体在C程序中主要用于优化存储空间的利用|实现多态|以及访问数据不同的内部表达方式.

63.一个指针, 在初始化为指向N个元素的存储空间之后, 就可以作为N个元素的数组来使用.

64.动态分配的内在块可以电焊工地释放, 或在程序结束时释放, 或由垃圾回收器来完成回收; 在栈上分配的内存块当分配它的函数退出后释放

65.C程序使用typedef声明促进抽象, 并增强代码的易读性, 从而防范可移植性问题, 并模拟C++和Java的类声明行为.

66.可以将typedef声明理解成变量定义: 变量的名称就是类型的名称; 变量的类型就是与该名称对应的类型.

+++++++++++++++

第四章: C数据结构

+++++++++++++++

67.根据底层的抽象数据类型理解显式的数据结构操作.

68.C语言中, 一般使用内建的数组类型实现向量, 不再对底层实现进行抽象.

69.N个元素的数组可以被序列for (i=0; i

70.表达式sizeof(x)总会得到用memset或memcpy处理数组x(不是指针)所需的正确字节数.

71.区间一般用区间内的第一个元素和区间后的第一个元素来表示.

72.不对称区间中元素的数目等于高位边界与低位边界的差.

73.当不对称区间的高位边界等于低位边界时, 区间为空.

74.不对称区间中的低位边界代表区间的第一个元素; 高位边界代表区间外的第一个元素.

75.结构的数组常常表示由记录和字段组成的表.

76.指向结构的指针常常表示访问底层记录和字段的游标.

77.动态分配的矩阵一般存储为指向数组列的指针或指向元素指针的指针; 这两种类型都可以按照二维数组进行访问.

78.以数组形式存储的动态分配矩阵, 用自定义访问函数定位它们的元素.

79.抽象数据类型为底层实现元素的使用(或误用)方式提供一种信心的量度.

80.数组用从0开始的顺序整数为键, 组织查找表.

81.数组经常用来对控制结构进行高效编码, 简化程序的逻辑.

82.通过在数组中每个位置存储一个数据元素和一个函数指针(指向处理数据元素的函数), 可以将代码与数据关联起来.

83.数组可以通过存储供程序内的抽象机(abstract machine)或虚拟机

(virtual machine)使用的数据或代码, 控制程序的运作.

84.可以将表达式sizeof(x) / sizeof(x[0])理解为数组x中元素的个数.

85.如果结构中含有指向结构自身|名为next的元素, 一般说来, 该结构定义的是单向链表的结点.

86.指向链表结点的持久性(如全局|静态或在堆上分配)指针常常表示链表的头部.

87.包含指向自身的next和prev指针的结构可能是双向链表的结点.

88.理解复杂数据结构的指针操作可以将数据元素画为方框|指针画为箭头.

89.递归数据结构经常用递归算法来处理.

90.重要的数据结构操作算法一般用函数参数或模板参数来参数化.

91.图的结点常常顺序地存储在数组中, 链接到链表中, 或通过图的边链接起来.

92.图中的边一般不是隐式地通过指针, 就是显式地作为独立的结构来表示.

93.图的边经常存储为动态分配的数组或链表, 在这两种情况下, 边都锚定在图的结点上.

94.在无向图中, 表达数据时应该将所有的结点看作是等同的, 类似地, 进行处理任务的代码也不应该基于它们的方向来区分边.

95.在非连通图中, 执行遍历代码应该能够接通孤立的子图.

96.处理包含回路的图时, 遍历代码应该避免在处理图的回路进入循环.

97.复杂的图结构中, 可能隐藏着其他类型的独立结构.

+++++++++++++++++

第五章: 高级控制流程

+++++++++++++++++

98.采用递归定义的算法和数据结构经常用递归的函数定义来实现.

99.推理递归函数时, 要从基准落伍测试开始, 并认证每次递归调用如何逐渐接近非递归基准范例代码.

100.简单的语言常常使用一系列遵循该语言语法结构的函数进行语法分析. 101.推理互递归函数时, 要基于底层概念的递归定义.

102.尾递归调用等同于一个回到函数开始处的循环.

103.将throws子句从方法的定义中移除, 然后运行Java编译器对类的源代码进行编译, 就可以容易地找到那些可能隐式地生成异常的方法.

104.在多处理器计算机上运行的代码常常围绕进程或线程进行组织.

105.工作群并行模型用于在多个处理器间分配工作, 或者创建一个任务池, 然后将大量需要处理标准化的工作进行分配.

106.基于线程的管理者/工人并行模型一般将耗时的或阻塞的操作分配给工人子任务, 从而维护中心任务的响应性.

107.基于进程的管理者/工人并行模型一般用来重用现有的程序, 或用定义良好的接口组织和分离粗粒度的系统模块.

108.基于流水线的并行处理中, 每个任务都接收到一些输入, 对它们进行一些处理, 并将生成的输出传递给下一个任务, 进行不同的处理.

109.竞争条件很难捉摸, 相关的代码常常会将竞争条件扩散到多个函数或模

块; 因而, 很难隔离由于竞争条件导致的问题.

110.对于出现在信号处理器中的数据结构操作代码和库调用要保持高度警惕. 111.在阅读包含宏的代码时, 要注意, 宏既非函数, 也非语句.

112.do…while(0)块中的宏等同于控制块中的语句.

113.宏可以访问在它的使用点可见的所有局部变量.

114.宏调用可改变参数的值

115.基于宏的标记拼接能够创建新的标记符.

+++++++++++++++++

第六章: 应对大型项目

+++++++++++++++++

116.我们可以通过浏览项目的源代码树—包含项目源代码的层次目录结构, 来分析一个项目的组织方式. 源码树常常能够反映出项目在构架和软件过程上的结构. 117.应用程序的源代码树经常是该应用程序的部署结构的镜像.

118.不要被庞大的源代码集合吓倒; 它们一般比小型的专门项目组织得更出色. 119.当您首次接触一个大型项目时, 要花一些时间来熟悉项目的目录树结构. 120.项目的源代码远不只是编译后可以获得可执行程序的计算机语言指令; 一个项目的源码树一般还包括规格说明|最终用户和开发人员文档|

测试脚本|多媒体资源|编译工具|例子|本地化文件|修订历史|安装过程和许可信息. 121.大型项目的编译过程一般声明性地借助依赖关系来说明. 依赖关系由工具程序, 如make及其派生程序, 转换成具体的编译行动.

122.大型项目中, 制作文件常常由配置步骤动态地生成; 在分析制作文件之前, 需要先执行项目特定的配置.

123.检查大型编译过程的各个步骤时, 可以使用make程序的-n开关进行预演. 124.修订控制系统提供从储存库中获取源代码最新版本的方式.

125.可以使用相关的命令, 显示可执行文件中的修订标识关键字, 从而将可执行

文件与它的源代码匹配起来.

126.使用修订日志中出现的bug跟踪系统内的编号, 可以在bug跟踪系统的数据库中找到有关的问题的说明.

127.可以使用修订控制系统的版本储存库, 找出特定的变更是如何实现的.

128.定制编译工具用在软件开发过程的许多方面, 包括配置|编译过程管理|代码

的生成|测试和文档编制.

129.程序的调试输出可以帮助我们理解程序控制流程和数据元素的关键部分. 130.跟踪语句所在的地点一般也是算法运行的重要部分.

131.可以用断言来检验算法运作的步骤|函数接收的参数|程序的控制流程|底层硬件的属性和测试用例的结果.

132.可以使用对算法进行检验的断言来证实您对算法运作的理解, 或将它作为推理的起点.

133.对函数参数和结果的断言经常记录了函数的前置条件和后置条件.

134.我们可以将测试整个函数的断言作为每个给定函数的规格说明.

135.测试用例可以部分地代替函数规格说明.

136.可以使用测试用例的输入数据对源代码序列进行预演.

+++++++++++++++++++

第七章: 编码规范和约定

+++++++++++++++++++

137.了解了给定代码库所遵循的文件组织方式后, 就能更有效率地浏览它的源代码.

138.阅读代码时, 首先要确保您的编辑器或优美打印程序的tab设置, 与代码遵循的风格规范一致.

139.可以使用代码块的缩进, 快速地掌握代码的总体结构.

140.对编排不一致的代码, 应该立即给予足够的警惕.

141.分析代码时, 对标记为XXX, FIXME和TODO的代码序列要格外注意: 错误可能就潜伏在其中.

142.常量使用大写字母命名, 单词用下划线分隔.

143.在遵循Java编码规范的程序中, 包名(package name)总是从一个顶级的域名开始(例如, org, com), 类名和接口名由大写字母开始, 方法和变量名由小写字母开始.

144.用户界面控件名称之前的匈牙利记法的前缀类型标记可以帮助我们确定它的作用.

145.不同的编程规范对可移植构造的构成有不同的主张.

146.在审查代码的可移植性, 或以某种给定的编码规范作为指南时, 要注意了解规范对可移植性需求的界定与限制.

147.如果GUI功能都使用相应的编程结构来实现, 则通过代码审查可以轻易地验证给定用户界面的规格说明是否被正确地采用.

148.了解项目编译过程的组织方式与自动化方式之后, 我们就能够快速地阅读与理解对应的编译规则.

149.当检查系统的发布过程时, 常常可以将相应发行格式的需求作为基准.

++++++++++++

第八章:文档

++++++++++++

150.阅读代码时, 应该尽可能地利用任何能够得到的文档.

151.阅读一小时代码所得到的信息只不过相当于阅读一分钟文档.

152.使用系统的规格说明文档, 了解所阅读代码的运行环境.

153.软件需求规格说明是阅读和评估代码的基准.

154.可以将系统的设计规格说明作为认知代码结构的路线图, 阅读具体代码的指引.

155.测试规格说明文档为我们提供可以用来对代码进行预演的数据.

156.在接触一个未知系统时, 功能性的描述和用户指南可以提供重要的背景信息,从而更好地理解阅读的代码所处的上下文.

157.从用户参考手册中, 我们可以快速地获取, 应用程序在外观与逻辑上的背景知识, 从管理员手册中可以得知代码的接口|文件格式和错误消息的详细信息. 158.利用文档可以快捷地获取系统的概况, 了解提供特定特性的代码.

159.文档经常能够反映和提示出系统的底层结构.

160.文档有助于理解复杂的算法和数据结构.

161.算法的文字描述能够使不透明(晦涩, 难以理解)的代码变得可以理解. 162.文档常常能够阐明源代码中标识符的含义.

163.文档能够提供非功能性需求背后的理论基础.

164.文档还会说明内部编程接口.

165.由于文档很少像实际的程序代码那样进行测试, 并受人关注, 所以它常常可能存在错误|不完整或过时.

166.文档也提供测试用例, 以及实际应用的例子.

167.文档常常还会包括已知的实现问题或bug.

168.环境中已知的缺点一般都会记录在源代码中.

169.文档的变更能够标出那些故障点.

170.对同一段源代码重复或互相冲突的更改, 常常表示存在根本性的设计缺陷, 从而使得维护人员需要用一系列的修补程序来修复.

171.相似的修复应用到源代码的不同部分, 常常表示一种易犯的错误或疏忽, 它们同样可能会在其他地方存在.

172.文档常常会提供不恰当的信息, 误导我们对源代码的理解.

173.要警惕那些未归档的特性: 将每个实例归类为合理|疏忽或有害, 相应地决定是否应该修复代码或文档.

174.有时, 文档在描述系统时, 并非按照已完成的实现, 而是系统应该的样子或将来的实现.

175.在源代码文档中, 单词gork的意思一般是指”理解”.

176.如果未知的或特殊用法的单词阻碍了对代码的理解, 可以试着在文档的术语表(如果存在的话)|New Hacker’s Dictionary[Ray96]|或在

Web搜索引擎中查找它们.

177.总是要以批判的态度来看待文档, 注意非传统的来源, 比如注释|标准|出版物|

测试用例|邮件列表|新闻组|修订日志|问题跟踪数据库|营销材料|源代码本身. 178.总是要以批判的态度来看待文档; 由于文档永远不会执行, 对文档的测试和

正式复查也很少达到对代码的同样水平, 所以文档常常会误导读者, 或者完全错误.

179.对于那些有缺陷的代码, 我们可以从中推断出它的真实意图.

180.在阅读大型系统的文档时, 首先要熟悉文档的总体结构和约定.

181.在对付体积庞大的文档时, 可以使用工具, 或将文本输出到高品质输出设备上, 比如激光打印机, 来提高阅读的效率.

++++++++++++++

第九章: 系统构架

++++++++++++++

182.一个系统可以(在重大的系统中也确实如此)同时出多种不同的构架类型. 以不同的方式检查同一系统|分析系统的不同部分|或使用不同级别的分解, 都有可能发现不同的构架类型.

183.协同式的应用程序, 或者需要协同访问共享信息或资源的半自治进程, 一般会采用集中式储存库构架.

184.黑板系统使用集中式的储存库, 存储非结构化的键/值对, 作为大量不同代码元件之间的通信集线器.

185.当处理过程可以建模|设计和实现成一系列的数据变换时, 常常会使用数据流(或管道—过滤器)构架.

186.在批量进行自动数据处理的环境中, 经常会采用数据流构架, 在对数据工具提供大量支持的平台上尤其如此.

187.数据流构架的一个明显征兆是: 程序中使用临时文件或流水线(pipeline)在不同进程间进行通信.

188.使用图示来建模面向对象构架中类的关系.

189.可以将源代码输入到建模工具中, 逆向推导出系统的构架.

190.拥有大量同级子系统的系统, 常常按照分层构架进行组织.

191.分层构架一般通过堆叠拥有标准化接口的软件组件来实现.

192.系统中每个层可以将下面的层看作抽象实体, 并且(只要该层满足它的需求说明)不关心上面的层如何使用它.

193.层的接口既可以是支持特定概念的互补函数族, 也可以是一系列支持同一抽象接口不同底层实现的可互换函数.

194.用C语言实现的系统, 常常用函数指针的数组, 表达层接口的多路复用操作.

195.用面向对象的语言实现的系统, 使用虚方法调用直接表达对层接口的多嘴复用操作.

196.系统可以使用不同的|独特的层次分解模型跨各种坐标轴进行组织.

197.使用程序切片技术, 可以将程序中的数据和控制之间依赖关系集中到一起.

198.在并发系统中, 一个单独的系统组件起到集中式管理器的作用, 负责启动|停止和协调其他系统进程和任务的执行.

199.许多现实的系统都会博采众家之长. 当处理此类系统时, 不要徒劳地寻找无所不包的构架图; 应该将不同构架风格作为独立但相关的实体来进行定位|识别并了解.

200.状态变迁图常常有助于理清状态机的动作.

201.在处理大量的代码时, 了解将代码分解成单独单元的机制极为重要.

202.大多数情况下, 模块的物理边界是单个文件|组织到一个目录中的多个文件或拥有统一前缀的文件的集合.

203.C中的模块, 由提供模块公开接口的头文件和提供对应实现的源文件组成.

204.对象的构造函数经常用来分配与对象相关的资源, 并初始化对象的状态. 函数一般用来释放对象在生命期中占用的资源.

205.对象方法经常使用类字段来存储控制所有方法运作的数据(比如查找表或字典)或维护类运作的状态信息(例如, 赋给每个对象一个标识符的计数器).

206.在设计良好的类中, 所有的字段都应在声明为private, 并用公开的访问方法提供对它们的访问.

207.在遇到friend声明时, 要停下来分析一下, 看看绕过类封装在设计上的理由.

208.可以有节制地用运算符增强特定类的可用性, 但用运算符重载, 将类实现为拥有内建算术类型相关的全部功能的类实体, 是不恰当的.

209.泛型实现不是在编译期间通过宏替换或语言所支持的功能(比如C++模板和Ada的泛型包)来实现, 就是在运行期间通过使用数据元素的指针和函数的指针|或对象的多态性实现.

210.抽象数据类型经常用来封装常用的数据组织方案(比如树|列表或栈), 或者对用户隐藏数据类型的实现细节.

211.使用库的目的多种多样: 重用源代码或目标代码, 组织模块集合, 组织和优化编译过程, 或是用来实现应用程序各种特性的按需载入.

212.大型的|分布式的系统经常实现为许多互相协作的进程.

213.对于基于文本的数据储存库, 可以通过浏览存储在其中的数据, 破译出它的结构.

214.可以通过查询数据字典中的表, 或使用数据库专有的SQL命令, 比如

show table, 来分析关系型数据库的模式.

215.识别出重用的构架元素后, 可以查找其最初的描述, 了解正确地使用这种构架的方式, 以及可能出现的误用.

216.要详细分析建立在某种框架之上的应用程序, 行动的最佳路线就是从研究框架自身开始.

217.在阅读向导生成的代码时, 不要期望太高, 否则您会感到失望.

218.学习几个基本的设计模式之后, 您会发现, 您查看代码构架的方式会发生改变: 您的视野和词汇将会扩展到能够识别和描述许多通用的形式.

219.频繁使用的一些模式, 但并不显式地指出它们的名称, 这是由于构架性设计的重用经常先于模式的形成.

220.请试着按照底层模式来理解构架, 即使代码中并没有明确地提及模式. 221.大多数解释器都遵循类似的处理构架, 围绕一个状态机进行构建, 状态机的操作依赖于解释器的当前状态|程序指令和程序状态.

222.多数情况下, 参考构架只是为应用程序域指定一种概念性的结构, 具体的实现并非必须遵照这种结构.

+++++++++++++++++

第十章: 代码阅读工具

+++++++++++++++++

223.词汇工具可以高效地在一个大代码文件中或者跨多个文件查找某种模式. 224.使用程序编辑器和正则表达式查找命令, 浏览庞大的源代码文件.

225.以只读方式浏览源代码文件.

226.使用正则表达式 ^function name 可以找出函数的定义.

227.使用正则表达式的字符类, 可以查找名称遵循特定模式的变量.

228.使用正则表达式的否定字符类, 可以避免非积极匹配.

229.使用正则表达式 symbol-1. *symbol-2, 可以查找出现在同一行的符号. 230.使用编辑器的 tags 功能, 可以快速地找出实体的定义.

231.可以用特定的 tag 创建工具, 增加编辑器的浏览功能.

232.使用编辑器的大纲视图, 可以获得源代码结构的鸟瞰图.

233.使用您的编辑器来检测源代码中圆括号|方括号和花括号的匹配.

234.使用 grep 跨多个文件查找代码模式.

235.使用 grep 定位符号的声明|定义和应用.

236.当您不能精确地表述要查找的内容时, 请使用关键单词的词干对程序的源代码进行查找.

237.用 grep 过滤其他工具生成的输出, 分离出您要查找的项.

238.将 grep 的输出输送到其他工具, 使复杂处理任务自动化.

239.通过对 grep 的输出进行流编辑, 重用代码查找的结果.

240.通过选取与噪音模式不匹配的输出行(grep-v), 过滤虚假的 grep 输出.

241.使用 fgrep 在源代码中查找字符串列表.

242.查找注释, 或标识符大小写不敏感的语言编写的代码时, 要使用大小写不敏感的模式匹配(grep -i).

243.使用 grep –n 命令行开关, 可以创建与给定正则表达式匹配的文件和行号的检查表.

244.可以使用 diff 比较文件或程序不同版本之间的差别.

245.在运行 diff 命令时, 可以使用 diff –b, 使文件比较算法忽略结尾的空

格, 用–w 忽略所有空白区域的差异, 用–i 使文件比较对大小写不敏感.

246.不要对创建自己的代码阅读工具心存畏惧.

247.在构建自己的代码阅读工具时: 要充分利用现代快速原型语言所提供的能力; 从简单开始, 根据需要逐渐改进; 使用利用代码词汇结构的

各种试探法; 要允许一些输出噪音或寂静(无关输出或缺失输出); 使用其他工具对输入进行预处理, 或者对输出进行后期处理.

248.要使编译器成为您的: 指定恰当级别的编译器警告, 并小心地评估生成的结果.

249.使用C预处理器理清那些滥用预处理器特性的程序.

250.要彻底地了解编译器如何处理特定的代码块, 需要查看生成的符号(汇编)代码.

251.通过分析相应目标文件中的符号, 可以清晰地了解源文件的输入和输出.

252.使用源代码浏览器浏览大型的代码集合以及对象类型.

253.要抵制住按照您的编码规范对外部代码进行美化的诱惑; 不必要的编排更改会创建不同的代码, 并妨碍工作的组织.

254.优美打印程序和编辑器语法着色可以使得程序的源代码为易读.

255.cdecl 程序可以将难以理解的C和C++类型声明转换成纯英语(反之亦然).

256.实际运行程序, 往往可以更深刻地理解程序的动作.

257.系统调用|事件和数据包跟踪程序可以增进对程序动作的理解.

258.执行剖析器可以找出需要着重优化的代码, 验证输入数据的覆盖性, 以及分析算法的动作.

259.通过检查从未执行的代码行, 可以找出测试覆盖的弱点, 并据此修正测试数据.

260.要探究程序动态动作时的每个细节, 需要在调试器中运作它.

261.将您觉得难以理解的代码打印到纸上.

262.可以绘制图示来描绘代码的动作.

263.可以试着向别人介绍您在阅读的代码, 这样做一般会增进您对代码的理解.

264.理解复杂的算法或巧妙的数据结构, 要选择一个安静的环境, 然后聚精会神地考虑, 不要借助于任何计算机化或自动化的帮助.

+++++++++++++++++++++

第十一章: 一个完整的例子

+++++++++++++++++++++

265.模仿软件的功能时, 要依照相似实体的线路(类|函数|模块). 在相似的现有实体中, 为简化对源代码库的文本查找, 应选取比较罕见的名称.

266.自动生成的文件常常会在文件的开关有一段注释, 说明这种情况.

267.如果试图精确地分析代码, 一般会陷入数量众多的类|文件和模块中, 这些内容会很快将我们淹没; 因此, 我们必须将需要理解的代码限定在绝对必需的范围之内.

268.采用一种广度优先查找策略, 从多方攻克代码阅读中存在的问题, 进到找出克服它们的方法为止.

如何阅读别人代码

如何阅读别人代码 code reading ++++++++++++ 第一章: 导论 ++++++++++++ 1.要养成一个习惯, 经常花时间阅读别人编写的高品质代码. 2.要有选择地阅读代码, 同时, 还要有自己的目标. 您是想学习新的模式|编码风格|还是满足某些需求的方法. 3.要注意并重视代码中特殊的非功能性需求, 这些需求也许会导致特殊的实现风格. 4.在现有的代码上工作时, 请与作者和维护人员进行必要的协调, 以避免重复劳动或产生厌恶情绪. 5.请将从开放源码软件中得到的益处看作是一项贷款, 尽可能地寻找各种方式来回报开放源码社团. 6.多数情况下, 如果您想要了解"别人会如何完成这个功能呢?", 除了阅读代码以外, 没有更好的方法. 7.在寻找bug时, 请从问题的表现形式到问题的根源来分析代码. 不要沿着不相关的路径(误入歧途). 8.我们要充分利用调试器|编译器给出的警告或输出的符号代码|系统调用跟踪器|数据库结构化查询语言的日志机制|包转储工具和Windows的消息侦查程序, 定出的bug的位置. 9.对于那些大型且组织良好的系统, 您只需要最低限度地了解它的全部功能, 就能够对它做出修改. 10.当向系统中增加新功能时, 首先的任务就是找到实现类似特性的代码, 将它作为待实现功能的模板. 11.从特性的功能描述到代码的实现, 可以按照字符串消息, 或使用关键词来搜索代码. 12.在移植代码或修改接口时, 您可以通过编译器直接定位出问题涉及的范围, 从而减少代码阅读的工作量. 13.进行重构时, 您从一个能够正常工作的系统开始做起, 希望确保结束时系统能

java 基础知识之hadoop源码阅读必备(一)

java 程序员你真的懂java吗? 一起来看下hadoop中的如何去使用java的 大数据是目前IT技术中最火热的话题,也是未来的行业方向,越来越多的人参与到大数据的学习行列中。从最基础的伪分布式环境搭建,再到分布式环境搭建,再进入代码的编写工作。这时候码农和大牛的分界点已经出现了,所谓的码农就是你让我做什么我就做什么,我只负责实现,不管原理,也不想知道原理。大牛就开始不听的问自己why?why?why?于是乎,很自然的去看源码了。然而像hadoop这样的源码N多人参与了修改和完善,看起来非常的吃力。然后不管如何大牛就是大牛,再硬的骨头也要啃。目前做大数据的80%都是从WEB开发转变过来的,什么spring mvc框架、SSH框架非常熟悉,其实不管你做了多少年的WEB开发,你很少接触到hadoop中java代码编写的风格,有些人根本就看不懂什么意思。下面我来介绍下hadoop源码怎么看。 hadoop体现的是分布式框架,因此所有的通信都基于RPC来操作,关于RPC的操作后续再介绍。hadoop源码怎么看系列分多个阶段介绍,下面重点介绍下JA V A基础知识。 一、多线程编程 在hadoop源码中,我们能看到大量的类似这样的代码 return executor.submit(new Callable() { @Override public String call() throws Exception { //方法类 } 下面简单介绍下java的多线程编程 启动一个线程可以使用下列几种方式 1、创建一个Runnable,来调度,返回结果为空。 ExecutorService executor = Executors.newFixedThreadPool(5); executor.submit(new Runnable() { @Override public void run() { System.out.println("runnable1 running."); } }); 这种方式启动一个线程后,在后台运行,不用等到结果,因为也不会返回结果 2、创建一个Callable,来调度,有返回结果 Future future1 = executor.submit(new Callable() { @Override public String call() throws Exception { // TODO Auto-generated method stub //具体执行一些内部操作 return "返回结果了!"; } }); System.out.println("task1: " + future1.get());

Linux 0.1.1文件系统的源码阅读

Linux 0.11文件系统的源码阅读总结 1.minix文件系统 对于linux 0.11内核的文件系统的开发,Linus主要参考了Andrew S.Tanenbaum 所写的《MINIX操作系统设计与实现》,使用的是其中的1.0版本的MINIX文件系统。而高速缓冲区的工作原理参见M.J.Bach的《UNIX操作系统设计》第三章内容。 通过对源代码的分析,我们可以将minix文件系统分为四个部分,如下如1-1。 ●高速缓冲区的管理程序。主要实现了对硬盘等块设备进行数据高速存取的函数。 ●文件系统的底层通用函数。包括文件索引节点的管理、磁盘数据块的分配和释放 以及文件名与i节点的转换算法。 ●有关对文件中的数据进行读写操作的函数。包括字符设备、块设备、管道、常规 文件的读写操作,由read_write.c函数进行总调度。 ●涉及到文件的系统调用接口的实现,这里主要涉及文件的打开、关闭、创建以及 文件目录等系统调用,分布在namei和inode等文件中。 图1-1 文件系统四部分之间关系图

1.1超级块 首先我们了解一下MINIX文件系统的组成,主要包括六部分。对于一个360K软盘,其各部分的分布如下图1-2所示: 图 1-2 建有MINIX文件系统的一个360K软盘中文件系统各部分的布局示意图 注释1:硬盘的一个扇区是512B,而文件系统的数据块正好是两个扇区。 注释2:引导块是计算机自动加电启动时可由ROM BIOS自动读入得执行代码和数据。 注释3:逻辑块一般是数据块的2幂次方倍数。MINIX文件系统的逻辑块和数据块同等大小 对于硬盘块设备,通常会划分几个分区,每个分区所存放的不同的文件系统。硬盘的第一个扇区是主引导扇区,其中存放着硬盘引导程序和分区表信息。分区表中得信息指明了硬盘上每个分区的类型、在硬盘中其实位置参数和结束位置参数以及占用的扇区总数。其结构如下图1-3所示。 图1-3 硬盘设备上的分区和文件系统 对于可以建立不同的多个文件系统的硬盘设备来说,minix文件系统引入超级块进行管理硬盘的文件系统结构信息。其结构如下图1-4所示。其中,s_ninodes表示设备上得i节点总数,s_nzones表示设备上的逻辑块为单位的总逻辑块数。s_imap_blocks 和s_zmap_blocks分别表示i节点位图和逻辑块位图所占用的磁盘块数。 s_firstdatazone表示设备上数据区开始处占用的第一个逻辑块块号。s_log_zone_size 是使用2为底的对数表示的每个逻辑块包含的磁盘块数。对于MINIX1.0文件系统该值为0,因此其逻辑块的大小就等于磁盘块大小。s_magic是文件系统魔幻数,用以指明文件系统的类型。对于MINIX1.0文件系统,它的魔幻数是0x137f。

源代码是什么

源代码是什么 源代码(也称源程序),是指一系列人类可读的计算机语言指令。在现代程序语言中,源代码可以是以书籍或者磁带的形式出现,但最为常用的格式是文本文件,这种典型格式的目的是为了编译出计算机程序。计算机源代码的最终目的是将人类可读的文本翻译成为计算机可以执行的二进制指令,这种过程叫做编译,通过编译器完成。 代码组合 源代码作为软件的特殊部分,可能被包含在一个或多个文件中。一个程序不必用同一种格式的源代码书写。例如,一个程序如果有C语言库的支持,那么就可以用C语言;而另一部分为了达到比较高的运行效率,则可以用汇编语言编写。较为复杂的软件,一般需要数十种甚至上百种的源代码的参与。为了降低种复杂度,必须引入一种可以描述各个源代码之间联系,并且如何正确编译的系统。在这样的背景下,修订控制系统(RCS)诞生了,并成为研发者对代码修订的必备工具之一。还有另外一种组合:源代码的编写和编译分别在不同的平台上实现,专业术语叫做软件移植。 质量 对于计算机而言,并不存在真正意义上的“好”的源代码;然而作为一个人,好的书写习惯将决定源代码的好坏。源代码是否具有可读性,成为好坏的重要标准。软件文档则是表明可读性的关键。 作用 源代码主要功用有如下2种作用: 生成目标代码,即计算机可以识别的代码。 对软件进行说明,即对软件的编写进行说明。为数不少的初学者,甚至少数有经验的程序员都忽视软件说明的编写,因为这部分虽然不会在生成的程序中直接显示,也不参与编译。但是说明对软件的学习、分享、维护和软件复用都有巨大的好处。因此,书写软件说明在业界被认为是能创造优秀程序的良好习惯,一些公司也硬性规定必须书写。

如何读源代码

如何阅读源代码 --转自CSDN_oncoding +++++++++++ 第一章: 导论 ++++++++++++ 1.要养成一个习惯, 经常花时间阅读别人编写的高品质代码. 2.要有选择地阅读代码, 同时, 还要有自己的目标. 您是想学习新的模式|编码风格|还是满足某些需求的方法. 3.要注意并重视代码中特殊的非功能性需求, 这些需求也许会导致特殊的实现风格. 4.在现有的代码上工作时, 请与作者和维护人员进行必要的协调, 以避免重复劳动或产生厌恶情绪. 5.请将从开放源码软件中得到的益处看作是一项贷款, 尽可能地寻找各种方式来回报开放源码社团. 6.多数情况下, 如果您想要了解"别人会如何完成这个功能呢?", 除了阅读代码以外, 没有更好的方法. 7.在寻找bug时, 请从问题的表现形式到问题的根源来分析代码. 不要沿着不相关的路径(误入歧途). 8.我们要充分利用调试器|编译器给出的警告或输出的符号代码|系统调用跟踪器|数据库结构化查询语言的日志机制|包转储工具和Windows的消息侦查程序, 定出的bug的位置. 9.对于那些大型且组织良好的系统, 您只需要最低限度地了解它的全部功能, 就能够对它做出修改. 10.当向系统中增加新功能时, 首先的任务就是找到实现类似特性的代码, 将它作为待实现功能的模板. 11.从特性的功能描述到代码的实现, 可以按照字符串消息, 或使用关键词来搜索代码. 12.在移植代码或修改接口时, 您可以通过编译器直接定位出问题涉及的范围, 从而减少代码阅读的工作量.

13.进行重构时, 您从一个能够正常工作的系统开始做起, 希望确保结束时系统能够正常工作. 一套恰当的测试用例(test case)可以帮助您满足此项约束. 14.阅读代码寻找重构机会时, 先从系统的构架开始, 然后逐步细化, 能够获得最大的效益. 15.代码的可重用性是一个很诱人, 但难以理解与分离, 可以试着寻找粒度更大一些的包, 甚至其他代码. 16.在复查软件系统时, 要注意, 系统是由很多部分组成的, 不仅仅只是执行语句. 还要注意分析以下内容: 文件和目录结构|生成和配置过程|用户界面和系统的文档. 18.可以将软件复查作为一个学习|讲授|援之以手和接受帮助的机会. ++++++++++++++++++++ 第二章: 基本编程元素 ++++++++++++++++++++ 19.第一次分析一个程序时, main是一个好的起始点. 20.层叠if-else if-...-else序列可以看作是由互斥选择项组成的选择结构. 21.有时, 要想了解程序在某一方面的功能, 运行它可能比阅读源代码更为恰当. 22.在分析重要的程序时, 最好首先识别出重要的组成部分. 23.了解局部的命名约定, 利用它们来猜测变量和函数的功能用途. 24.当基于猜测修改代码时, 您应该设计能够验证最初假设的过程. 这个过程可能包括用编译器进行检查|引入断言|或者执行适当的测试用例. 25.理解了代码的某一部分, 可能帮助你理解余下的代码. 26.解决困难的代码要从容易的部分入手. 27.要养成遇到库元素就去阅读相关文档的习惯; 这将会增强您阅读和编写代码的能力. 28.代码阅读有许多可选择的策略: 自底向上和自顶向下的分析|应用试探法和检查注释和外部文档, 应该依据问题的需要尝试所有这些方法. 29.for (i=0; i

如何看懂源代码--(分析源代码方法)

如何看懂源代码--(分析源代码方法) 4 推 荐 由于今日计划着要看Struts 开源框架的源代码 昨天看了一个小时稍微有点头绪,可是这个速度本人表示非常不满意,先去找了下资 料, 觉得不错... 摘自(繁体中文 Traditional Chinese):http://203.208.39.132/translate_c?hl=zh-CN&sl=en&tl=zh-CN&u=http://ww https://www.sodocs.net/doc/0d578808.html,/itadm/article.php%3Fc%3D47717&prev=hp&rurl=https://www.sodocs.net/doc/0d578808.html,&usg=AL kJrhh4NPO-l6S3OZZlc5hOcEQGQ0nwKA 下文为经过Google翻译过的简体中文版: 我们在写程式时,有不少时间都是在看别人的代码。 例如看小组的代码,看小组整合的守则,若一开始没规划怎么看,就会“噜看噜苦(台语)”不管是参考也好,从开源抓下来研究也好,为了了解箇中含意,在有限的时间下,不免会对庞大的源代码解读感到压力。网路上有一篇关于分析看代码的方法,做为程式设计师的您,不妨参考看看,换个角度来分析。也能更有效率的解读你想要的程式码片段。 六个章节: ( 1 )读懂程式码,使心法皆为我所用。( 2 )摸清架构,便可轻松掌握全貌。( 3 )优质工具在手,读懂程式非难事。( 4 )望文生义,进而推敲组件的作用。( 5 )找到程式入口,再由上而下抽丝剥茧。( 6 )阅读的乐趣,透过程式码认识作者。 程式码是别人写的,只有原作者才真的了解程式码的用途及涵义。许多程式人心里都有一种不自觉的恐惧感,深怕被迫去碰触其他人所写的程式码。但是,与其抗拒接收别人的程式码,不如彻底了解相关的语言和惯例,当成是培养自我实力的基石。 对大多数的程式人来说,撰写程式码或许是令人开心的一件事情,但我相信,有更多人视阅读他人所写成的程式码为畏途。许多人宁可自己重新写过一遍程式码,也不愿意接收别人的程式码,进而修正错误,维护它们,甚至加强功能。 这其中的关键究竟在何处呢?若是一语道破,其实也很简单,程式码是别人写的,只有原作者才真的了解程式码的用途及涵义。许多程式人心里都有一种不自觉的恐惧感,深怕被迫去碰触其他人所写的程式码。这是来自于人类内心深处对于陌生事物的原始恐惧。 读懂别人写的程式码,让你收获满满 不过,基于许多现实的原因,程式人时常受迫要去接收别人的程式码。例如,同事离职了,必须接手他遗留下来的工作,也有可能你是刚进部门的菜鸟,而同事经验值够了,升级了,风水轮流转,一代菜鸟换菜鸟。甚至,你的公司所承接的专案,必须接手或是整合客户前一个厂商所遗留下来的系统,你们手上只有那套系统的原始码(运气好时,还有数量不等的文件)。 诸如此类的故事,其实时常在程式人身边或身上持续上演着。许多程式人都将接手他人的程式码,当做一件悲惨的事情。每个人都不想接手别人所撰写的程式码,因为不想花时间去探索,宁可将生产力花在产生新的程式码,而不是耗费在了解这些程式码上。

教你如何读懂源代码

分析源代码方法 如何看懂源代码--(分析源代码方法> 我们在写程序时,有不少时间都是在看别人的代码。 例如看小组的代码,看小组整合的守则,若一开始没规划怎么看, 就会“噜看噜苦<台语)” 不管是参考也好,从开源抓下来研究也好,为了了解箇中含意,在有限的时间下,不免会对庞大的源代码解读感到压力。 网路上有一篇关于分析看代码的方法,做为程序设计师的您,不妨参考看看, 换个角度来分析。也能更有效率的解读你想要的程序码片段。 六个章节:< 1 )读懂程序码,使心法皆为我所用。< 2 )摸清架构,便可轻松掌握全貌。< 3 )优质工具在手,读懂程序非难事。< 4 )望文生义,进而推敲组件的作用。< 5 )找到程序入口,再由上而下抽丝剥茧。< 6 )阅读的乐趣,透过程

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

程序员阅读源代码的5种方法

程序员阅读源代码的5种方法 摘要:不吃猪肉也看过猪爬树,阅读好的源代码,可以大幅度提高程序员小伙伴们的编程水平。因为研究源代码其一可以让你学习代码的架构,其二可以让你明白算法是如何实现的。 关键词:源代码程序员 代码中自有黄金屋,代码中自由颜如玉。 不吃猪肉也看过猪爬树,阅读好的源代码,可以大幅度提高程序员小伙伴们的编程水平。

因为研究源代码其一可以让你学习代码的架构,其二可以让你明白算法是如何实现的。 程序员阅读源代码的5种方法,阅读源代码要带哪些目的? 下面给程序员小伙伴们分享阅读源代码的5种奇技淫巧: 0、读代码时刻思考这两个问题 读代码理应是抱着一定的目的阅读。你应该时刻思考: A、代码要解决的问题是什么? B 、代码是如何实现的? 程序员阅读源代码的5种方法,阅读源代码要带哪些目的? 1、让代码飞起来 我们除了阅读代码,运行代码是必不可少的。 唯有运行代码,你才能清楚它使用的库、它所依赖的开发框架等。

2、对代码做些调查 阅读代码理应具备立体感。也就说,我们需要从整体的角度去审视代码。 所以,我们不妨对代码做些调查。譬如看官网介绍,也可以参考维基百科。 总之一定要了解主要功能,被应用于哪些项目,其实这就是弄清代码的一个背景问题。 程序员阅读源代码的5种方法,阅读源代码要带哪些目的? 3、重视代码 人和人之间是有差距的,这一点必须承认。有人会说,读源代码没有用,前提是人家会造轮子。 当你要说阅读源代码没用时,应当反思:自己能否造轮子? 4、带着目的阅读代码

阅读代码最怕陷进去,源代码从头读到尾,结果看的云里雾里的。 最重要的是带着目的阅读。搞清楚为什么要阅读代码?你要学习架构、学习业务、学习模式、学习编码风格、学习类库还是什么? 设置一些小目标,这可以让你进阶得更快。

Source Insight:Linux源代码阅读的利器

阅读源代码是钻研技术的最佳手段,而Linux提供了一个庞大的源代码库,但是,由于缺乏良好的源代码阅读工具,使得阅读Linux源代码尤其是内核源代码十分困难,在本文中,笔者向大家推荐一个优秀的源代码阅读工具,并介绍了它的使用方法。 作为一个开放源代码的操作系统,Linux附带的源代码库使得广大爱好者有了一个广泛学习、深入钻研的机会,特别是Linux内核的组织极为复杂,同时,又不能像windows平台的程序一样,可以使用集成开发环境通过察看变量和函数,甚至设置断点、单步运行、调试等手段来弄清楚整个程序的组织结构,使得Linux内核源代码的阅读变得尤为困难。 当然Linux下的vim和emacs编辑程序并不是没有提供变量、函数搜索,彩色显示程序语句等功能。它们的功能是非常强大的。比如,vim和emacs就各自内嵌了一个标记程序,分别叫做ctag和etag,通过配置这两个程序,也可以实现功能强大的函数变量搜索功能,但是由于其配置复杂,linux附带的有关资料也不是很详细,而且,即使建立好标记库,要实现代码彩色显示功能,仍然需要进一步的配置(在另一片文章,我将会讲述如何配置这些功能),同时,对于大多数爱好者来说,可能还不能熟练使用vim和emacs那些功能比较强大的命令和快捷键。 为了方便的学习Linux源程序,我们不妨回到我们熟悉的window环境下,也算是“师以长夷以制夷”吧。但是在Window平台上,使用一些常见的集成开发环境,效果也不是很理想,比如难以将所有的文件加进去,查找速度缓慢,对于非Windows平台的函数不能彩色显示。于是笔者通过在互联网上搜索,终于找 到了一个强大的源代码编辑器,它的卓越性能使得学习Linux内核源代码的难度大大降低,这便是Source Insight3.0,它是一个Windows平台下的共享软件,可以从https://www.sodocs.net/doc/0d578808.html,/上边下载30天试用版本。也可以在 https://www.sodocs.net/doc/0d578808.html,/index.php?option=com_remository&Itemid=67&func=fileinfo &parent=folder&filecatid=3由于Source Insight是一个Windows平台的应用软件,所以首先要通过相应手段把Linux系统上的程序源代码弄到Windows平台下,这一点可以通过在linux平台上将/usr/src目录下的文件拷贝到Windows平台的分区上,或者从网上光盘直接拷贝文件到Windows平台的分区来实现。 下面主要讲解如何使用Source Insight,考虑到阅读源程序的爱好者都有相当的软件使用水平,本文 对于一些琐碎、人所共知的细节略过不提,仅介绍一些主要内容,以便大家能够很快熟练使用本软件,减少摸索的过程。 安装Source Insight并启动程序,可以进入图1界面。在工具条上有几个值得注意的地方,如图所示,图中内凹左边的是工程按钮,用于显示工程窗口的情况;右边的那个按钮按下去将会显示一个窗口,里边提供光标所在的函数体内对其他函数的调用图,通过点击该窗体里那些函数就可以进入该函数所在的地方。

别人的原代码程序员怎样阅读

别人的原代码程序员怎样阅读 源码就是指编写的最原始程序的代码。运行的软件是要经过编写的,程序员编写程序的过程中需要他们的“语言”。音乐家用五线谱,建筑师用图纸,那程序员的工作的语言就是“源码”了。人们平时使用软件时就是程序把“源码”翻译成我们可直观的形式表现出来供我们使用的。任何一个网站页面,换成源码就是一堆按一定格式书写的文字和符号,但我们的浏览器帮我们翻译成眼前的模样了。 计算机里面运行的所有东西都是用程序编出来的(包括操作系统,如Windows,还有Word等,网络游戏也一样),而编写程序要用到计算机语言,用计算机语言直接编出来的程序就叫源码,比如用VisualBasic编写的源码文件一般为.bas文件,而用C++编写的一般为.cpp文件,源代码不能直接在Windows下运行,必须编译后才能运行。源码经过编译处理后就可以直接在操作系统下运行了。很多的站长都喜欢使用建网站的程序源码,因为可以很方便的修改,对于任何一个seo人员来说,都是非常好的一个切入点。从字面意义上来讲,源文件是指一个文件,指源代码的集合.源代码则是一组具有特定意义的可以实现特定功能的字符(程序开发代码),源代码”在大多数时候等于“源文件”。比如在这个网页上右键鼠标,选择查看源文件.出来一个记事本,里面的内容就是此网页的源代码."这句话就体现了他们的关系,此处的源文件是指网页的源文件,而源代码就是源文件的内容,所以又可以称做网页的源代码..,源代码是指原始代码,可以是任何语言代码。汇编码是指源代码编译后的代码,通常为二进制文件,比如DLL、EXE、.NET中间代码、JAVA中间代码等。高级语言通常指C/C++、BASIC、C#、JAVA、PASCAL、易语言等等。汇编语言就是ASM,只有这个,比这个更低级的就是机器语言了。 网站源码作为软件的特殊部分,可能被包含在一个或多个文件中。一个程序不必用同一种格式的源代码书写。例如,一个程序如果有C语言库的支持,那么就可以用C语言;而另一部分为了达到比较高的运行效率,则可以用汇编语言编写。较为复杂的软件,一般需要数十种甚至上百种的源代码的参与。为了降低种复杂度,必须引入一种可以描述各个源代码之间联系,并且如何正确编译的系统。在这样的背景下,修订控制系统(RCS)诞生了,并成为研发者对代码修订的必备工具之一。还有另外一种组合:源代码的编写和编译分别在不同的平台上实现,专业术语叫做软件移植。 阅读别人的代码作为开发人员是一件经常要做的事情。一个是学习新的编程语言的时候通过阅读别人的代码是一个最好的学习方法,另外是积累编程经验。如果你有机会阅读一些操作系统的代码会帮助你理解一些基本的原理。还有就是在你作为一个质量保证人员或一个小领导的时候如果你要做白盒测试的时

OpenvSwitch源码阅读笔记-SDNLAB

Open vSwitch源码阅读笔记 引言 本文主要对OpenvSwitch(基于2.3.90版本)重点模块的源码实现流程做了简要的阅读记录,适合阅读OpenvSwitch源码的初级读者参考使用,任何错误和建议欢迎加作者QQ 号38293996沟通交流。 1. OVS网络架构 Openvswitch是一个虚拟交换机,支持Open Flow协议(也有一些硬件交换机支持Open Flow),他们被远端的controller通过Open Flow协议统一管理着,从而实现对接入的虚拟机(或设备)进行组网和互通,整体组网结构如下图: 2. OVS内部架构

●ovs-vswitchd 主要模块,实现vswitch的守候进程daemon; ●ovsdb-server 轻量级数据库服务器,用于ovs的配置信息; ●ovs-vsctl 通过和ovsdb-server通信,查询和更新vswitch的配置; ●ovs-dpctl 用来配置vswitch内核模块的一个工具; ●ovs-appctl 发送命令消息到ovs进程; ●ovs-ofctl 查询和控制OpenFlow虚拟交换机的流表; ●datapath 内核模块,根据流表匹配结果做相应处理; 3. OVS代码架构

●vswitchd是ovs主要的用户态程序,它从ovsdb-server读取配置并发送到ofproto 层,也从ofproto读取特定的状态和统计信息并发送到数据库; ●ofproto是openflow的接口层,负责和Openflow controller通信并通过 ofproto_class与ofproto provider底层交互; ●ofproto-dpif是ofproto接口类的具体实现; ●netdev是ovs系统的网络设备抽象(比如linux的net_device或交换机的port), netdev_class定义了netdev-provider的具体实现需要的接口,具体的平台实现需要支持这些统一的接口,从而完成netdev设备的创建、销毁、打开、关闭等一系列操作; 3.1 datapath 由于openvswitch用户态代码相对复杂,首先从内核模块入手分析。 datapath为 ovs内核模块,负责执行数据处理,也就是把从接收端口收到的数据 包在流表中进行匹配,并执行匹配到的动作。一个datapath可以对应多个vport,一个vport类似物理交换机的端口概念。一个datapth关联一个flow table,一个flow table 包含多个条目,每个条目包括两个内容:一个match/key和一个action。 3.1.1 数据流向

LINUX源代码阅读报告

进程调度代码分析 ——关于LINUX源代码中进程调度部分的读书报告 在多进程的操作系统中,进程调度是一个全局性、关键性的问题,它对系统的总体设计、系统的的实现、功能设置以及各个方面的性能都有着决定性的影响。根据调度的结果所作的进程切换的速度,也是衡量一个操作系统性能的重要指标。进程调度机制的设计,还对系统的复杂性有着极大的影响,常常会由于实现的复杂程度而在功能与性能方面作出必要的权衡和让步。 一.进程调度的基本原理 一个好的系统的进程调度机制,应当考虑以下几个问题: (1)公平:保证每个进程得到合理的CPU 时间。 (2)高效:使CPU 保持忙碌状态,即总是有进程在CPU 上运行。 (3)响应时间:使交互用户的响应时间尽可能短。 (4)周转时间:使批处理用户等待输出的时间尽可能短。 (5)吞吐量:使单位时间内处理的进程数量尽可能多。 显然,要同时满足这几个方面是不可能的,所以,形成一个操作系统就必须在这几个方面中做出权衡和必要的取舍,从而确定自己的调度算法。例如:UNIX采用动态优先数调度,5.3BSD采用舵机反馈队列调度,windows采用抢先多任务调度。 为了满足以上五个方面,设计一个进程调度机制时要考虑以下问题: (1)调度的时机:在什么情况什么时候进行调度; (2)调度的“政策”(policy):根据什么准则挑选下一个进入运行的进程; (3)调度的方式:是抢占的,还是非抢占的。 对于一个进程,其状态转换关系图具体如下所示:

Linux 的调度程序是一个叫Schedule()的函数,这个函数被调用的频率很高,由它来决定是否要进行进程的切换,如果要切换的话,切换到哪个进程等。即调度时机:Linux 调度时机主要有: (1)进程状态转换的时刻:进程终止、进程睡眠; (2)当前进程的时间片用完时(current->counter=0); (3)设备驱动程序; (4)进程从中断、异常及系统调用返回到用户态时。 时机1,进程要调用sleep()或exit()等函数进行状态转换,这些函数会主动调用调度程序进行进程调度。 时机2,由于进程的时间片是由时钟中断来更新的,因此,这种情况和时机4 是一样的。 时机3,当设备驱动程序执行长而重复的任务时,直接调用调度程序。在每次反复循环中,驱动程序都检查need_resched的值,如果必要,则调用调度程序schedule()主动放弃CPU。 时机4,不管是从中断、异常还是系统调用返回,最终都调ret_from_sys_call(),由这个函数进行调度标志的检测,如果必要,则调用调用调度程序。考虑到效率,则必须从系统调用返回时要调用调度程序。从系统调用返回意味着要离开内核态而返回到用户态,而状态的转换要花费一定的时间,因此,在返回到用户态前,系统把在内核态该处理的事全部做完。 在操作系统课程当中,我们已经了解到了六种调度算法,下面进行简单的介绍: A.先到先服务(first come ,first served, FCFS) B.最短作业优先调度(shortest-job-first, SJF) (a)抢占的SJF; (b)非抢占的SJF; C.优先权调度(priority-scheduling algorithm) D.轮转法(round-robin, RR) E.多级队列调度(multilevel queue-scheduling algorithm) F.多级反馈队列调度(multilevel feedback queue scheduling algorithm) 在实时系统中,广泛采用抢占调度方式,特别是对于那些要求严格的实时系统。因为这种调度方式既具有较大的灵活性,又能获得很小的调度延迟;但是这种调度方式也比较复杂。二.LINUX进程调度的源代码分析 在LINUX内核中,所有的调度方式基本上都是从UNIX继承下来的以优先级为基础的调度。内核为系统中的每个进程计算出一个反映其运行资格的权值(即优先级),然后挑选其权值最高的进程投入运行。在运行过程中,当前进程的资格随时间而递减,从而在下一次调度的时候原来资格较低的进程可能就更有资格运行了。到所有的权值都为0时,则重新计算所有进程的资格。 为了适应各种不同的应用的需要,内核在此基础上实现了三种不同的调度策略:SCHED_FIFO、SCHED_RR以及SCHED_OTHER。每个进程都有自己适用的调度算法,并且,进程还可以通过系统调用sched_setscheduler()设定自己使用的调度政策。其中SCHED_FIFO适合于时间性要求比较强,但每一次运行所需的时间比较短的进程,实时的应用大都具有这样的特点。SCHED_RR适合每次运行需要时间很长的进程。SCHED_OTHER则是传统的调度算法,比较适合于交互式的分时应用。 下面是对内核代码中的sched.c进行分段的分析:

php学习方法-如何阅读php源代码

php学习方法-如何阅读php源代码 2011-10-28 22:58:47| 分类:PHP | 标签:|举报|字号大中小订阅 php技术的快速进步,最好的途径就是阅读源代码了。自己也阅读了很多开源的程序,感觉方法很重要,好的方法可以达到事半功倍的效果。 一份好的源代码例如dz的论坛,wind论坛,帝国cms,dedecms等,都具有自己的一套设计思路和设计模式,所以在看某个产品之前就要做好心理准备,可以把自己的经验和这些产品做对比,但千万别一直用自己的思维去评判。一句话就是“以学习和批评的辩证思想去看待”。 那具体的我们怎样去阅读一份php的源代码呢? 一。先把源代码安装起来,结合它的文档和手册,熟悉其功能和它的应用方式。 二。浏览源代码的目录结构,了解各个目录的功能。 三。经过以上两步后相信你对这个开源的产品有了一个初步的了解了,那现在就开始分析它的源码吧。这一步我们开始分析源代码框架。例如入口方式是单入口还是多入口,页面之间的调用规则,能根据规则找出某个功能用到的页面。 四。熟悉源代码的代码写作风格,例如缩进方式,排版格式等。 五。熟悉一下源代码用到的数据库和表,可以参考它的技术支持文档。 六。经过以上几步相信大家已经对这份源代码有了更深刻的了解,不过这种了解还只是表面的,下来我们从6个方面具体的去分析它吧: 1.入口构造以及页面调用方式的具体实现,如果阅读时看到工具类和工具函数,尽量去熟悉一下。这一步的分析可以学习到源代码的系统架构方式。 2.分析源代码用到的工具类和工具函数,这样可以学到很多程序编写技巧。可以提升自己编程功力。 3.结合一些安全规则,研究这个源代码是怎样实现安全方面的设计的。这样可以提高自己在安全方面的意识和功力。 4.如果有模板引擎的话,研究一下源代码的模板引擎。大致从实现方式,效率,易用性等几个方面去考虑。 5.研究系统的各个功能模块,这样既能学习编程技巧还能打开自己的编程思路,下次遇到类似的东东就心里有谱了。 6.研究系统所用到设计模式,一样的功能实现,用到的设计模式可能相差很多,对比我们之前所作的东东分析设计模式,是提升我们驾驭代码的不二法门。 7.研究源代码对访问压力,执行效率,系统效率,数据库查询的优化。 方法只是途径和工具,具体实践还需要大家的努力。自己的感想是不要着急,认真分析,把分析心得用到自己的具体项目上。

linux内核源码阅读工具eclipse qemu

linux内核源码阅读工具eclipse + qemu 一linux内核源码阅读工具windows下当然首选source insight,但是linux下就没有source insight这么优秀的工具了,但是也有不少的替代品,但觉绝对部分人会选择 vim+ctags+cscope的组合,还有部分人或选择wine中的source insight或选择navigatror,当然对于代码阅读来说vim+ctags+cscope的组合还是比较好的一个选择方案,但是,当我使用了eclipse之后,个人感觉用eclipse作为linux 环境下源码阅读工具确实比vim+ctags+cscope的组合方便很多。下面是linux环境下eclipse的配置安装方案:eclipse 下载地址: https://www.sodocs.net/doc/0d578808.html,/downloads/?osType=linuxeclipse环境配置方案: https://www.sodocs.net/doc/0d578808.html,/viewtopic.php?t=183803二eclipse + qemu 进行linux源码的编译和调试最初调试内核采用了qemu + insight 或qemu + ddd的组合,相比来说insgiht的界面更加有好些,但是ubuntu 10.04以上的版本,删除了对Insight的默认支持,只能下载insight的源码编译安装,而且insight更新非常慢。很久以前就看到有人用eclipse + qemu进行linux内核源码的编译和调试,这次终于抽了个时间尝试一下,毕竟eclipse的debugger是非常强

大的。工具组合:Eclipse IDE for C/C++ Linux Developers + qemu-0.12.3 (最好用kvm, 不幸的是机器太旧,不支持硬件虚拟化) 1.首先我们要从https://www.sodocs.net/doc/0d578808.html,下载内核源码,在这里我选择的是linux-2.6.32.tar.bz2。我将其下载到我的主目录下,然后在terminal下输入以下命令。$ cd (回到主目录)$ tar xf linux-2.6.32.tar.bz2 (解压源码)$ mkdir linux-2.6.32-obj (创建一个编译内核的目标文件输出目录)$ cd linux-2.6.32 (进入内核源码树根目录)$ make O=~/linux-2.6.28-obj menuconfig (这里我们要配置内核,并在~/linux-2.6.32-obj目录下生成内核配置文 件.config)$ make mrproper 2. 接下来我们打开elicpse,第一次打开时有一个欢迎画面,我们单击右边的workbench 图片关掉欢迎画面。由于eclipse cdt是一个非常强大的 c/c++ ide,它默认会自动的解析工程中源程序并编译工程和产生智能提示信息。但由于我们调试内核过程中暂不会用到这些功能,所以要关闭他们。首先我们到 Window->Preferences->General->Workspace 中将Build Automatically选项去掉。然后到 Window->Preferences->C/C++ -> Indexer中,将默认的Fast c/c++ indexer改为No indexer。然后我们开始创建一个新的工程。从菜单中选择File -> New -> Project… -> C/C++ -> C Project 然后单击Next按钮。

源代码是什么

我们电脑上安装的软件都是目标程序。除了脚本语言的源程序外,其他源程序是不能直接运行的。 提倡软件开源的人士认为应该提供源程序给用户,让用户自己修改,有利于软件行业的发展。反对的人觉得这样不利于保护版权。 你如果不懂编程,源程序可以不管它。不影响正常使用。 源代码作为软件的特殊部分,可能被包含在一个或多个文件中。一个程序不必用同一种格式的源代码书写。例如,一个程序如果有C语言库的支持,那么就可以用C语言;而另一部分为了达到比较高的运行效率,则可以用汇编语言编写。 较为复杂的软件,源程序文件可以达到成千上万个。为了降低复杂度,必须引入一种可以描述各个源代码之间联系,并且如何正确编译的系统。在这样的背景下,修订控制系统(RCS)诞生了,并成为研发者对代码修订的必备工具之一。 还有另外一种组合:源代码的编写和编译分别在不同的平台上实现,专业术语叫做软件移植。关于开放源代码的定义以及解释 作者:王立来源:eNet硅谷动力 【译者的声明】 本文是开放源代码定义、开放源代码定义原理以及OSI Certified标志与纲要的中文译文。本文由王立在1999年8月翻译。本人在翻译时为确保译文与原文在含义上一致性付出了最大努力,但是本人不能对由于译文与原文在含义上的差异而造成的任何误解或对译文的误解所造成的任何直接的、间接的损失承担任何责任。 开放源代码并不仅仅意味着对源代码的访问权。开放源代码软件的发布条款必须满足以下条件: 我们认为本开放源代码定义涵盖了由绝大多数软件团体使用的术语"开放源代码"的最初含义和当前含义。然而,该术语被广泛地应用,并且它的含义变得不精确了。OSI Certified 标志是某个软件发布许可证是否服从开放源代码定义的OST认证方式。一般的术语"开放源代码"并不提供这种担保,但我们仍然鼓励使用"开放源代码"这一术语以表明它符合"开放源代码定义"。关于OSI Certified标志的信息,以及已经通过了OSI Certified、符合"开放源代码定义"的许可证,请参见OSI Certified标志与纲要。 【开放源代码定义之原理】 给出开放源代码的定义的目的是:把我们所确信的、由软件开发团体所公认的"开放源代码"的含义作为一组具体的准则写下来---该准则确保按照开放源代码许可证发布的软件可以得到与其它软件同样认真的评审、使软件可以不断地得到改良和遴选,从而提供非开放软件所难以提供的可靠性与能力。为了使此项工作持续发展,我们必须抵制人们为了短期利益而中止为软件开发做出贡献。这意味着,许可证的条款必须防止人们藏匿(lock up)源代码从而导致只有很少的人才能够阅读和修改它。当软件的开发者按照由OSI认证的许可证发布他们的软件时,他们可以在软件中使用"OSI Certified"标志。这种认证标志告知用户,该软件所采用的许可证符合开放源代码定义。关于我们的认证标志的更多信息及其纲要,请参见OSI Certified标志与纲要。 1.自由地再发布 通过强制要求许可证允许自由地再发布,我们抵制了任何为了获得少量短期销售金额而放弃长期效益的诱惑。如果我们不这样做,就会有很多压力迫使合作者放弃承诺。 2.源代码 由于软件只有通过修改才能够得到改进,因此我们要求获得易于理解的源代码。因为我们的目的是使软件易于改进,我们也就希望软件易于修改。 3.派生作品

如何阅读Linux源码

如何阅读Linux源码 Linux内核的配置系统由三个部分组成,分别是: Makefile:分布在Linux 内核源代码中的Makefile,定义Linux 内核的编译规则;? 配置文件(config.in):给用户提供配置选择的功能;? 配置工具:包括配置命令解释器(对配置脚本中使用的配置命令进行解释)和配置用户界面(提供基于字符界面、基于Ncurses 图形界面以及基于Xwindows 图形界面的用户配置界面,各自对应于Make config、Make menuconfig 和make xconfig)。? 这些配置工具都是使用脚本语言,如Tcl/TK、Perl 编写的(也包含一些用 C 编写的代码)。本文并不是对配置系统本身进行分析,而是介绍如何使用配置系统。所以,除非是配置系统的维护者,一般的内核开发者无须了解它们的原理,只需要知道如何编写Makefile 和配置文件就可以。所以,在本文中,我们只对Makefile 和配置文件进行讨论。另外,凡是涉及到与具体CPU 体系结构相关的内容,我们都以ARM 为例,这样不仅可以将讨论的问题明确化,而且对内容本身不产生影响。 2.Makefile 2.1 Makefile 概述 Makefile 的作用是根据配置的情况,构造出需要编译的源文件列表,然后分别编译,并把目标代码链接到一起,最终形成Linux 内核二进制文件。 由于Linux 内核源代码是按照树形结构组织的,所以Makefile 也被分布在目录树中。Linux 内核中的Makefile 以及与Makefile 直接相关的文件有: Makefile:顶层Makefile,是整个内核配置、编译的总体控制文件。? .config:内核配置文件,包含由用户选择的配置选项,用来存放内核配置后的结果(如make config)。? arch/*/Makefile:位于各种CPU 体系目录下的Makefile,如arch/arm/Makefile,是针对特定平台的Makefile。? 各个子目录下的Makefile:比如drivers/Makefile,负责所在子目录下源代码的管理。?Rules.make:规则文件,被所有的Makefile 使用。? 用户通过make config 配置后,产生了 .config。顶层Makefile 读入 .config 中的配置选择。顶层Makefile 有两个主要的任务:产生vmlinux 文件和内核模块(module)。为了达到此目的,顶层Makefile 递归的进入到内核的各个子目录中,分别调用位于这些子目录中的Makefile。至于到底进入哪些子目录,取决于内核的配置。在顶层Makefile 中,有一句:include arch/$(ARCH)/Makefile,包含了特定CPU 体系结构下的Makefile,这个Makefile 中包含了平台相关的信息。 位于各个子目录下的Makefile 同样也根据 .config 给出的配置信息,构造出当前配置下需要的源文件列表,并在文件的最后有include $(TOPDIR)/Rules.make。 Rules.make 文件起着非常重要的作用,它定义了所有Makefile 共用的编译规则。比如,如果需要将本目录下所有的 c 程序编译成汇编代码,需要在Makefile 中有以下的编译规则:%.s: %.c $(CC) $(CFLAGS) -S $< -o $@ 有很多子目录下都有同样的要求,就需要在各自的Makefile 中包含此编译规则,这会比较麻

相关主题