日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

阅读源码技术与艺术五

發(fā)布時(shí)間:2025/3/20 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 阅读源码技术与艺术五 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
如果該日期、時(shí)間沒(méi)有錯(cuò)誤,則該數(shù)據(jù)是一個(gè)好的數(shù)據(jù),將good_record計(jì)數(shù)器加1,并且檢查時(shí)間戳,和數(shù)據(jù)是否重復(fù)數(shù)據(jù)。這里有一個(gè)函數(shù),jdate()在主程序一開(kāi)頭我們就遇到了,當(dāng)時(shí)跳了過(guò)去沒(méi)有深究,這里留給讀者做一個(gè)練習(xí)。(提示:該函數(shù)根據(jù)一個(gè)日期產(chǎn)生一個(gè)字符串,這個(gè)字符串是惟一的,可以檢查時(shí)間的重復(fù)性,是一個(gè)通用函數(shù),可以在別的程序中拿來(lái)使用)


/*********************************************/
/* DO SOME PRE-PROCESS FORMATTING */
/*********************************************/
/* fix URL field */
cp1 = cp2 = log_rec.url;
/* handle null '-' case here... */
if (*++cp1 == '-') { *cp2++ = '-'; *cp2 = ''; }
else
{
/* strip actual URL out of request */
while ( (*cp1 != ' ') && (*cp1 != '') ) cp1++;
if (*cp1 != '')
{
/* scan to begin of actual URL field */
while ((*cp1 == ' ') && (*cp1 != '')) cp1++;
/* remove duplicate / if needed */
if (( *cp1=='/') && (*(cp1+1)=='/')) cp1++;
while ((*cp1 != ' ')&&(*cp1 != '"')&&(*cp1 != ''))
*cp2++ = *cp1++;
*cp2 = '';
}
}
/* un-escape URL */
unescape(log_rec.url);
/* check for service (ie: http://) and lowercase if found */
if ( (cp2=strstr(log_rec.url,"://")) != NULL)
{
cp1=log_rec.url;
while (cp1!=cp2)
{
if ( (*cp1>='A') && (*cp1<='Z')) *cp1 += 'a'-'A';
cp1++;
}
}
/* strip query portion of cgi scripts */
cp1 = log_rec.url;
while (*cp1 != '')
if (!isurlchar(*cp1)) { *cp1 = ''; break; }
else cp1++;
if (log_rec.url[0]=='')
{ log_rec.url[0]='/'; log_rec.url[1]=''; }
/* strip off index.html (or any aliases) */
lptr=index_alias;
while (lptr!=NULL)
{
if ((cp1=strstr(log_rec.url,lptr->string))!=NULL)
{
if ((cp1==log_rec.url)||(*(cp1-1)=='/'))
{
*cp1='';
if (log_rec.url[0]=='')
{ log_rec.url[0]='/'; log_rec.url[1]=''; }
break;
}
}
lptr=lptr->next;
}
/* unescape referrer */
unescape(log_rec.refer);
......

?

  這一段,做了一些URL字符串中的字符轉(zhuǎn)換工作,很長(zhǎng),我個(gè)人認(rèn)為為了程序的模塊化,結(jié)構(gòu)化和可復(fù)用性,應(yīng)該將這一段代碼改為函數(shù),避免主程序體太長(zhǎng),造成可讀性不強(qiáng)和沒(méi)有移植性,和不夠結(jié)構(gòu)化。跳過(guò)這一段乏味的代碼,進(jìn)入到下面一個(gè)部分---后處理。


if (gz_log) gzclose(gzlog_fp);
else if (log_fname) fclose(log_fp);
if (good_rec) /* were any good records? */
{
tm_site[cur_day-1]=dt_site; /* If yes, clean up a bit */
tm_visit[cur_day-1]=tot_visit(sd_htab);
t_visit=tot_visit(sm_htab);
if (ht_hit > mh_hit) mh_hit = ht_hit;
if (total_rec > (total_ignore+total_bad))
/* did we process any? */
{
if (incremental)
{
if (save_state()) /* incremental stuff */
{
/* Error: Unable to save current run data */
if (verbose) fprintf(stderr,"%s ",msg_data_err);
unlink(state_fname);
}
}
month_update_exit(rec_tstamp); /* calculate exit pages */
write_month_html(); /* write monthly HTML file */
write_main_index(); /* write main HTML file */
put_history(); /* write history */
}
end_time = times(&mytms);
/* display timing totals? */
if (time_me' '(verbose>1))
{
printf("%lu %s ",total_rec, msg_records);
if (total_ignore)
{
printf("(%lu %s",total_ignore,msg_ignored);
if (total_bad) printf(", %lu %s) ",total_bad,msg_bad);
else printf(") ");
}
else if (total_bad) printf("(%lu %s) ",total_bad,msg_bad);
/* get processing time (end-start) */
temp_time = (float)(end_time-start_time)/CLK_TCK;
printf("%s %.2f %s", msg_in, temp_time, msg_seconds);
/* calculate records per second */
if (temp_time)
i=( (int)( (float)total_rec/temp_time ) );
else i=0;
if ( (i>0) && (i<=total_rec) ) printf(", %d/sec ", i);
else printf(" ");
}

?

  這一段,做了一些后期的處理。接下來(lái)的部分,我想在本文中略過(guò),留給感興趣的讀者自己去做分析。原因有兩點(diǎn):

1、這個(gè)程序在前面結(jié)構(gòu)化比較強(qiáng),而到了結(jié)構(gòu)上后面有些亂,雖然代碼效率還是比較高,但是可重用性不夠強(qiáng), 限于篇幅,我就不再一一解釋了。 2、前面分析程序過(guò)程中,也對(duì)后面的代碼做了一些預(yù)測(cè)和估計(jì),也略微涉及到了后面的代碼,而且讀者可以根據(jù)上面提到的原則來(lái)自己分析代碼,也作為一個(gè)實(shí)踐吧。
  最后,對(duì)于在這篇文章中提到的分析源代碼程序的一些方法做一下小結(jié),以作為本文的結(jié)束。

  分析一個(gè)源代碼,一個(gè)有效的方法是:

  1、閱讀源代碼的說(shuō)明文檔,比如本例中的README, 作者寫(xiě)的非常的詳細(xì),仔細(xì)讀過(guò)之后,在閱讀程序的時(shí)候往往能夠從README文件中找到相應(yīng)的說(shuō)明,從而簡(jiǎn)化了源程序的閱讀工作。

  2、如果源代碼有文檔目錄,一般為doc或者docs, 最好也在閱讀源程序之前仔細(xì)閱讀,因?yàn)檫@些文檔同樣起了很好的說(shuō)明注釋作用。

  3、從makefile文件入手,分析源代碼的層次結(jié)構(gòu),找出哪個(gè)是主程序,哪些是函數(shù)包。這對(duì)于快速把握程序結(jié)構(gòu)有很大幫助。

  4、從main函數(shù)入手,一步一步往下閱讀,遇到可以猜測(cè)出意思來(lái)的簡(jiǎn)單的函數(shù),可以跳過(guò)。但是一定要注意程序中使用的全局變量(如果是C程序),可以把關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)說(shuō)明拷貝到一個(gè)文本編輯器中以便隨時(shí)查找。

  5、分析函數(shù)包(針對(duì)C程序),要注意哪些是全局函數(shù),哪些是內(nèi)部使用的函數(shù),注意extern關(guān)鍵字。對(duì)于變量,也需要同樣注意。先分析清楚內(nèi)部函數(shù),再來(lái)分析外部函數(shù),因?yàn)閮?nèi)部函數(shù)肯定是在外部函數(shù)中被調(diào)用的。

  6、需要說(shuō)明的是數(shù)據(jù)結(jié)構(gòu)的重要性:對(duì)于一個(gè)C程序來(lái)說(shuō),所有的函數(shù)都是在操作同一些數(shù)據(jù),而由于沒(méi)有較好的封裝性,這些數(shù)據(jù)可能出現(xiàn)在程序的任何地方,被任何函數(shù)修改,所以一定要注意這些數(shù)據(jù)的定義和意義,也要注意是哪些函數(shù)在對(duì)它們進(jìn)行操作,做了哪些改變。

  7、在閱讀程序的同時(shí),最好能夠把程序存入到cvs之類的版本控制器中去,在需要的時(shí)候可以對(duì)源代碼做一些修改試驗(yàn),因?yàn)閯?dòng)手修改是比僅僅是閱讀要好得多的讀程序的方法。在你修改運(yùn)行程序的時(shí)候,可以從cvs中把原來(lái)的代碼調(diào)出來(lái)與你改動(dòng)的部分進(jìn)行比較(diff命令), 可以看出一些源代碼的優(yōu)缺點(diǎn)并且能夠?qū)嶋H的練習(xí)自己的編程技術(shù)。

  8、閱讀程序的同時(shí),要注意一些小工具的使用,能夠提高速度,比如vi中的查找功能,模式匹配查找,做標(biāo)記,還有g(shù)rep,find這兩個(gè)最強(qiáng)大最常用的文本搜索工具的使用。

  對(duì)于一個(gè)Unix/Linux下面以命令行方式運(yùn)行的程序,有這么一些套路,大家可以在閱讀程序的時(shí)候作為參考。

  1、在程序開(kāi)頭,往往都是分析命令行,根據(jù)命令行參數(shù)對(duì)一些變量或者數(shù)組,或者結(jié)構(gòu)賦值,后面的程序就是根據(jù)這些變量來(lái)進(jìn)行不同的操作。

  2、分析命令行之后,進(jìn)行數(shù)據(jù)準(zhǔn)備,往往是計(jì)數(shù)器清空,結(jié)構(gòu)清零等等。

  3、在程序中間有一些預(yù)編譯選項(xiàng),可以在makefile中找到相應(yīng)部分。

  4、注意程序中對(duì)于日志的處理,和調(diào)試選項(xiàng)打開(kāi)的時(shí)候做的動(dòng)作,這些對(duì)于調(diào)試程序有很大的幫助。

  5、注意多線程對(duì)數(shù)據(jù)的操作。(這在本例中沒(méi)有涉及)

  結(jié)束語(yǔ):

  當(dāng)然,在這篇文章中,并沒(méi)有闡述所有的閱讀源代碼的方法和技巧,也沒(méi)有涉及任何輔助工具(除了簡(jiǎn)單的文本編輯器),也沒(méi)有涉及面向?qū)ο蟪绦虻拈喿x方法。我想把這些留到以后再做討論。也請(qǐng)大家可以就這些話題展開(kāi)討論。

總結(jié)

以上是生活随笔為你收集整理的阅读源码技术与艺术五的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。