分享
 
 
 

如何阅读源代码

王朝other·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

写在前面的话:

自从我在linuxaid.com.cn上发表一些文章开始,就不断的有网友发来电子邮件,或者是就其中某些问题进行探讨,或者是查询其他文章的地址(往往这些网友看的是其他网站转载的我的文章),我很高兴自己写出的文章有这么多人回应,因为这是对我最好的赞赏,也很高兴有这么多人对我的文章感兴趣。但是常常因为工作关系。有很多邮件是询问我的其他文章在哪里能够找到,我不一定能够及时回复,也觉得回复同样的问题比较麻烦,所以在这里重复一下,我为linuxaid.com.cn写的文章都能在www.linuxaid.com.cn的应用开发栏目中找到,我的一部分文章收集在bambi.may10.ca/~ariesram/articles下面(这是一个很简陋的网页,只有文本格式的文章,也欢迎有兴趣的网友帮我设计一下网页),我的邮件地址:ariesram@linuxaid.com.cn, 或者ariesram@may10.ca。请转载文章的网站保留这一说明,欢迎网友写email给我探讨问题,虽然我不能保证能及时回复。

正文:

由于工作的关系,我常常需要读一些源代码,并在上面做一些修改并且拿来使用,或者是借鉴其中的某些部分。可以说,open source对于程序员来说,是很有意义的事情。根据我的经验,读源代码,至少有3个好处。第一个好处是可以学习到很多编程的方法,看好的源代码,对于提高自己的编程水平,比自己写源代码的帮助更大。当然不是说不用自己写,而是说,自己写代码的同时,可以从别人写的好的源代码中间学习到更多的编程方法和技巧。第二个好处是,可以提高自己把握大规模源代码的能力。一个比较大型的程序,往往都是经过了很多个版本很长的时间,有很多人参与开发,修正错误,添加功能而发展起来的。所以往往源代码的规模都比较大,少则10-100多k, 多的有好几十个MB. 在阅读大量源代码的时候,能够提高自己对大的软件的把握能力,快速了解脉络,熟悉细节,不仅仅是编程技巧,还能在程序的架构,设计方面提高自己的能力。(这里说一句题外话,<<设计模式>>这本书相信很多人都看过,而且很多人对它推崇备至,奉为经典。现在也出了不少书,都是冠以"设计模式"这一名称。在书中就提到,设计模式并不是一本教材,不是教你如何去编程序,而是把平时编程中一些固定的模式记录下来,加以不断的测试和改进,分发给广大程序员的一些经验之谈。我在看这本书的时候,有一些地方一些设计方法往往让我有似曾相识的感觉,另外一些则是我以前就常常用到的。而这些经验的获得,一部分得益于自己的编码过程,另外一个很重要的来源就是阅读别人写的源代码。)阅读源代码第三个好处,就是获得一些好的思想。比如,有很多人在开始一个软件项目之前都喜欢到sourceforge.net上去找一下,是否有人以前做过相同或者相似的软件,如果有,则拿下来读一读,可以使自己对这个软件项目有更多更深的认识。我以前曾经想找一本关于如何阅读源代码的书来看看,却没有找到。相反,倒是找到了不少分析源代码的书,比如Linux kernel, Apache source, 等等。所以我想,为什么不自己来写下一些经验和大家交流呢?(当然不是写书,没有那个能力也没有那个时间。)所以在这里我准备用一个例子来写一下如何阅读源代码,分享一些经验,算是抛砖引玉吧!

我找的例子是一个统计日志的工具,webalizer. (这个工具我以前用过,似乎记得以前的版本是用perl写的,不知道现在为什么作者把它完全修改成了C,可能是为了效率,也可能根本就是我记错了。)之所以选择这个软件来作为例子,一方面是因为它是用C写的,流程比较简单,没有C++的程序那么多的枝节,而且软件功能不算复杂,代码规模不大,能够在一篇文章的篇幅里面讲完; 另外一个方面是因为恰巧前段时间我因为工作的关系把它拿来修改了一下,刚看过,还没有忘记。 :-)我采用的例子是webalizer2.01-09, 也可以到它的网站http://www.mrunix.net/webalizer/ 下载最新的版本。这是一个用C写的,处理文本文件(简单的说是这样,实际上它支持三种日志文本格式:CLF, FTP, SQUID), 并且用html的方式输出结果。读者可以自己去下载它的源代码包,并一边读文章,一边看程序。解压缩它的tar包(我download的是它的源代码tar包),在文件目录中看到这样的结果:

$ ls

aclocal.m4 dns_resolv.c lang output.h webalizer.1

CHANGES dns_resolv.h lang.h parser.c webalizer.c

configure graphs.c linklist.c parser.h webalizer.h

configure.in graphs.h linklist.h preserve.c webalizer_lang.h

COPYING hashtab.c Makefile.in preserve.h webalizer.LSM

Copyright hashtab.h Makefile.std README webalizer.png

country-codes.txt INSTALL msfree.png README.FIRST

DNS.README install-sh output.c sample.conf

首先,我阅读了它的README(这是很重要的一个环节), 大体了解了软件的功能,历史状况,修改日志,安装方法等等。然后是安装并且按照说明中的缺省方式来运行它,看看它的输出结果。(安装比较简单,因为它带了一个configure, 在没有特殊情况出现的时候,简单的./configure, make, make install就可以安装好。)然后就是阅读源代码了。我从makefile开始入手(我觉得这是了解一个软件的最好的方法)在makefile开头,有这些内容:

prefix = /usr/local

exec_prefix = ${prefix}

BINDIR = ${exec_prefix}/bin

MANDIR = ${prefix}/man/man1

ETCDIR = /etc

CC = gcc

CFLAGS = -Wall -O2

LIBS = -lgd -lpng -lz -lm

DEFS = -DETCDIR="/etc" -DHAVE_GETOPT_H=1 -DHAVE_MATH_H=1

LDFLAGS=

INSTALL= /usr/bin/install -c

INSTALL_PROGRAM=${INSTALL}

INSTALL_DATA=${INSTALL} -m 644

# where are the GD header files?

GDLIB=/usr/include

这些定义了安装的路径,执行程序的安装路径,编译器,配置文件的安装路径,编译的选项,安装程序,安装程序的选项等等。要注意的是,这些并不是软件的作者写的,而是./configure的输出结果。呵呵. :-)下面才是主题内容,也是我们关心的。

# Shouldn't have to touch below here!

all: webalizer

webalizer: webalizer.o webalizer.h hashtab.o hashtab.h

linklist.o linklist.h preserve.o preserve.h

dns_resolv.o dns_resolv.h parser.o parser.h

output.o output.h graphs.o graphs.h lang.h

webalizer_lang.h

$(CC) ${LDFLAGS} -o webalizer webalizer.o hashtab.o linklist.o preserv

e.o parser.o output.o dns_resolv.o graphs.o ${LIBS}

rm -f webazolver

ln -s webalizer webazolver

webalizer.o: webalizer.c webalizer.h parser.h output.h preserve.h

graphs.h dns_resolv.h webalizer_lang.h

$(CC) ${CFLAGS} ${DEFS} -c webalizer.c

parser.o: parser.c parser.h webalizer.h lang.h

$(CC) ${CFLAGS} ${DEFS} -c parser.c

hashtab.o: hashtab.c hashtab.h dns_resolv.h webalizer.h lang.h

$(CC) ${CFLAGS} ${DEFS} -c hashtab.c

linklist.o: linklist.c linklist.h webalizer.h lang.h

$(CC) ${CFLAGS} ${DEFS} -c linklist.c

output.o: output.c output.h webalizer.h preserve.h

hashtab.h graphs.h lang.h

$(CC) ${CFLAGS} ${DEFS} -c output.c

preserve.o: preserve.c preserve.h webalizer.h parser.h

hashtab.h graphs.h lang.h

$(CC) ${CFLAGS} ${DEFS} -c preserve.c

dns_resolv.o: dns_resolv.c dns_resolv.h lang.h webalizer.h

$(CC) ${CFLAGS} ${DEFS} -c dns_resolv.c

graphs.o: graphs.c graphs.h webalizer.h lang.h

$(CC) ${CFLAGS} ${DEFS} -I${GDLIB} -c graphs.c

好了,不用再往下看了,这些就已经足够了。从这里我们可以看到这个软件的几个源代码文件和他们的结构。webalizer.c是主程序所在的文件,其他的是一些辅助程序模块。对比一下目录里面的文件,

$ ls *.c *.h

dns_resolv.c graphs.h lang.h output.c parser.h webalizer.c

dns_resolv.h hashtab.c linklist.c output.h preserve.c webalizer.h

graphs.c hashtab.h linklist.h parser.c preserve.h webalizer_lang.h

于是,让我们从webalizer.c开始吧。

作为一个C程序,在头文件里面,和C文件里面定义的extern变量,结构等等肯定不会少,但是,单独看这些东西我们不可能对这个程序有什么认识。所以,从main函数入手,逐步分析,在需要的时候再回头来看这些数据结构定义才是好的方法。(顺便说一句,Visual C++, 等windows下的IDE工具提供了很方便的方法来获取函数列表,C++的类列表以及资源文件,对于阅读源代码很有帮助。Unix/Linux也有这些工具,但是,我们在这里暂时不说,而只是通过最简单的文本编辑器vi来讲)。跳过webalizer.c开头的版权说明部分(GPL的),和数据结构定义,全局变量声明部分,直接进入main()函数。在函数开头,我们看到:

/* initalize epoch */

epoch=jdate(1,1,1970); /* used for timestamp adj. */

/* add default index. alias */

add_nlist("index.",&index_alias);

这两个函数暂时不用仔细看,后面会提到,略过。

sprintf(tmp_buf,"%s/webalizer.conf",ETCDIR);

/* check for default config file */

if (!access("webalizer.conf",F_OK))

get_config("webalizer.conf");

else if (!access(tmp_buf,F_OK))

get_config(tmp_buf);

从注释和程序本身可以看出,这是查找是否存在一个叫做webalizer.conf的配置文件,如果当前目录下有,则用get_config来读入其中内容,如果没有,则查找ETCDIR/webalizer.conf是否存在。如果都没有,则进入下一部分。(注意:ETCDIR = @ETCDIR@在makefile中有定义)

/* get command line options */

opterr = 0; /* disable parser errors */

while ((i=getopt(argc,argv,"a:A:c:C:dD:e:E:fF:

g:GhHiI:l:Lm:M:n:N:o:pP:qQr:R:s:S:t:Tu:U:vVx:XY"))!=EOF)

{

switch (i)

{

case 'a': add_nlist(optarg,&hidden_agents); break;

/* Hide agents */

case 'A': ntop_agents=atoi(optarg); break;

/* Top agents */

case 'c': get_config(optarg); break;

/* Config file */

case 'C': ntop_ctrys=atoi(optarg); break;

/* Top countries */

case 'd': debug_mode=1; break;

/* Debug */

case 'D': dns_cache=optarg; break;

/* DNS Cache filename */

case 'e': ntop_entry=atoi(optarg); break;

/* Top entry pages */

case 'E': ntop_exit=atoi(optarg); break;

/* Top exit pages */

case 'f': fold_seq_err=1; break;

/* Fold sequence errs */

case 'F': log_type=(optarg[0]=='f')?

LOG_FTP:(optarg[0]=='s')?

LOG_SQUID:LOG_CLF; break;

/* define log type */

case 'g': group_domains=atoi(optarg); break;

/* GroupDomains (0=no) */

case 'G': hourly_graph=0; break;

/* no hourly graph */

case 'h': print_opts(argv[0]); break;

/* help */

case 'H': hourly_stats=0; break;

/* no hourly stats */

case 'i': ignore_hist=1; break;

/* Ignore history */

case 'I': add_nlist(optarg,&index_alias); break;

/* Index alias */

case 'l': graph_lines=atoi(optarg); break;

/* Graph Lines */

case 'L': graph_legend=0; break;

/* Graph Legends */

case 'm': visit_timeout=atoi(optarg); break;

/* Visit Timeout */

case 'M': mangle_agent=atoi(optarg); break;

/* mangle user agents */

case 'n': hname=optarg; break;

/* Hostname */

case 'N': dns_children=atoi(optarg); break;

/* # of DNS children */

case 'o': out_dir=optarg; break;

/* Output directory */

case 'p': incremental=1; break;

/* Incremental run */

case 'P': add_nlist(optarg,&page_type); break;

/* page view types */

case 'q': verbose=1; break;

/* Quiet (verbose=1) */

case 'Q': verbose=0; break;

/* Really Quiet */

case 'r': add_nlist(optarg,&hidden_refs); break;

/* Hide referrer */

case 'R': ntop_refs=atoi(optarg); break;

/* Top referrers */

case 's': add_nlist(optarg,&hidden_sites); break;

/* Hide site */

case 'S': ntop_sites=atoi(optarg); break;

/* Top sites */

case 't': msg_title=optarg; break;

/* Report title */

case 'T': time_me=1; break; /* TimeMe */

case 'u': add_nlist(optarg,&hidden_urls); break;

/* hide URL */

[1] [2] [3] [4] 下一页

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有