計算機等級考試四級上機編程修養(中)

1、著作權和版本
———————
好的程式設計師會給自己的每個函式,每個檔案,都註上著作權和版本。

對於c/c 的檔案,檔案頭應該有類似這樣的注釋:
/************************************************************************
*
* 檔案名稱:network.c
*
* 檔案描述:網路通訊函式集
*
* 創建人: hao chen, 2003年2月3日
*
* 版本號:1.0
*
* 修改記錄:
*
*
************************************************************************/

而對於函式來說,應該也有類似於這樣的注釋:

/*================================================================
*
* 函 數 名:xxx
*
* 參 數:
*
* type name [in] : descripts
*
* 功能描述:
*
* ..............
*
* 返 回 值:成功true,失敗false
*
* 拋出異常:
*
* 作 者:chenhao 2003/4/2
*
*
================================================================*/



這樣的描述可以讓人對一個函式,一個檔案有一個總體的認識,對代碼的易讀性和易維護
性有很大的好處。這是好的作品產生的開始。

2、縮進、空格、換行、空行、對齊
————————————————
i) 縮進應該是每個程式都會做的,只要學程式過程式就應該知道這個,但是我仍然看過不
縮進的程式,或是亂縮進的程式,如果你的公司還有寫程式不縮進的程式設計師,請毫不猶豫
的開除他吧,並以破壞源碼罪起訴他,還要他賠償讀過他程式的人的精神損失費。縮進,
這是不成文規矩,我再重提一下吧,一個縮進一般是一個tab鍵或是4個空格。(最好用tab
鍵)

ii) 空格。空格能給程式代來什麼損失嗎?沒有,有效的利用空格可以讓你的程式讀進來
更加賞心悅目。而不一堆表達式擠在一起。看看下面的代碼:

ha=(ha*128 *key )%tabptr->size;

ha = ( ha * 128 *key ) % tabptr->size;

有空格和沒有空格的感覺不一樣吧。一般來說,語句中要在各個操作符間加空格,函
數調用時,要以各個參數間加空格。如下面這種加空格的和不加的:

if ((hproc=openprocess(process_all_access,false,pid))==null){
}

if ( ( hproc = openprocess(process_all_access, false, pid) ) == null ){
}


iii) 換行。不要把語句都寫在一行上,這樣很不好。如:

for(i=0;i<len;i ) if((a[i]<’0’||a[i]>’9’)&&(a[i]<’a’||a[i]>’z’)) break;

我拷,這種即無空格,又無換行的程式在寫什麼啊?加上空格和換行吧。

for ( i=0; i<len; i ) {
if ( ( a[i] < ’0’ || a[i] > ’9’ ) &&
( a[i] < ’a’ || a[i] > ’z’ ) ) {
break;
}
}


好多了吧?有時候,函式參數多的時候,最好也換行,如:
createprocess(
null,
cmdbuf,
null,
null,
binhh,
dwcrtflags,
envbuf,
null,
&sistartinfo,
&prinfo
);



條件語句也應該在必要時換行:

if ( ch >= ’0’ || ch <= ’9’ ||
ch >= ’a’ || ch <= ’z’ ||
ch >= ’a’ || ch <= ’z’ )


iv) 空行。不要不加空行,空行可以區分不同的程式塊,程式塊間,最好加上空行。如:


handle hprocess;
process_t procinfo;

/* open the process handle */
if((hprocess = openprocess(process_all_access, false, pid)) == null)
{
return lse_misc_sys;
}

memset(&procinfo, 0, sizeof(procinfo));
procinfo.idproc = pid;
procinfo.hdproc = hprocess;
procinfo.misc |= msc***a_proc;

return(0);



v) 對齊。用tab鍵對齊你的一些變數的聲明或注釋,一樣會讓你的程式好看一些。如:

typedef struct _pt_man_t_ {
int numproc; /* number of processes */
int maxproc; /* max number of processes */
int maxproc; /* max number of processes */
int numevnt; /* number of events */
int maxevnt; /* max number of events */
handle* phndevnt; /* array of events */
dword timeout; /* time out interval */
handle hpipe; /* namedpipe */
tchar usr[maxusr];/* user name of the process */
int nummsg; /* number of message */
int msg[maxmsg];/* space for intro process communicate */
} pt_man_t;

怎么樣?感覺不錯吧。

這裡主要講述了如果寫出讓人賞心悅目的代碼,好看的代碼會讓人的心情愉快,讀起代碼
也就不累,工整、整潔的程式代碼,通常更讓人歡迎,也更讓人稱道。現在的硬碟空間這
么大,不要讓你的代碼擠在一起,這樣它們會抱怨你虐待它們的。好了,用“縮進、空格
、換行、空行、對齊”裝飾你的代碼吧,讓他們從沒有秩序的土匪中變成一排排整齊有秩
序的正規部隊吧。


3、程式注釋
——————
養成寫程式注釋的習慣,這是每個程式設計師所必須要做的工作。我看過那種幾千行,卻居然
沒有一行注釋的程式。這就如同在公路上駕車卻沒有路標一樣。用不了多久,連自己都不
知道自己的意圖了,還要花上幾倍的時 間才看明白,這種浪費別人和自己的時 間的人,是
最為可恥的人。

是的,你也許會說,你會寫注釋,真的嗎?注釋的書寫也能看出一個程式設計師的功底。一般
來說你需要至少寫這些地方的注釋:檔案的注釋、函式的注釋、變數的注釋、算法的注釋
、功能塊的程式注釋。主要就是記錄你這段程式是乾什麼的?你的意圖是什麼?你這個變
量是用來做什麼的?等等。

不要以為注釋好寫,有一些算法是很難說或寫出來的,只能意會,我承認有這種情況的時
候,但你也要寫出來,正好可以訓練一下自己的表達能力。而表達能力正是那種悶頭搞技
術的技術人員最缺的,你有再高的技術,如果你表達能力不行,你的技術將不能得到充分
的發揮。因為,這是一個團隊的時代。

好了,說幾個注釋的技術細節:

i) 對於行注釋(“//”)比塊注釋(“/* */”)要好的說法,我並不是很同意。因為一
些老版本的c編譯器並不支持行注釋,所以為了你的程式的移植性,請你還是儘量使用塊注
釋。


ii) 你也許會為塊注釋的不能嵌套而不爽,那么你可以用預編譯來完成這個功能。使用“#
if 0”和“#endif”括起來的代碼,將不被編譯,而且還可以嵌套。

4、函式的[in][out]參數
———————————

我經常看到這樣的程式:
funcname(char* str)
{
int len = strlen(str);
.....
}

char*
getusername(struct user* puser)
{
return puser->name;
}


不!請不要這樣做。
你應該先判斷一下傳進來的那個指針是不是為空。如果傳進來的指針為空的話,那么,你
的一個大的系統就會因為這一個小的函式而崩潰。一種更好的技術是使用斷言(assert)
,這裡我就不多說這些技術細節了。當然,如果是在c 中,引用要比指針好得多,但你也
需要對各個參數進行檢查。

寫有參數的函式時,首要工作,就是要對傳進來的所有參數進行合法性檢查。而對於傳出
的參數也應該進行檢查,這個動作當然應該在函式的外部,也就是說,調用完一個函式後
,應該對其傳出的值進行檢查。

當然,檢查會浪費一點時 間,但為了整個系統不至於出現“非法操作”或是“core dump”
的系統級的錯誤,多花這點時 間還是很值得的。

5、對系統調用的返回進行判斷
——————————————
繼續上一條,對於一些系統調用,比如打開檔案,我經常看到,許多程式設計師對fopen返回的
指針不做任何判斷,就直接使用了。然後發現檔案的內容怎么也讀出不,或是怎么也寫不
進去。還是判斷一下吧:

fp = fopen("log.txt", "a");
if ( fp == null ){
printf("error: open file error\n");
return false;
}

其它還有許多啦,比如:socket返回的socket號,malloc返回的記憶體。請對這些系統調用
返回的東西進行判斷。

1、著作權和版本
———————
好的程式設計師會給自己的每個函式,每個檔案,都註上著作權和版本。

對於c/c 的檔案,檔案頭應該有類似這樣的注釋:
/************************************************************************
*
* 檔案名稱:network.c
*
* 檔案描述:網路通訊函式集
*
* 創建人: hao chen, 2003年2月3日
*
* 版本號:1.0
*
* 修改記錄:
*
*
************************************************************************/

而對於函式來說,應該也有類似於這樣的注釋:

/*================================================================
*
* 函 數 名:xxx
*
* 參 數:
*
* type name [in] : descripts
*
* 功能描述:
*
* ..............
*
* 返 回 值:成功true,失敗false
*
* 拋出異常:
*
* 作 者:chenhao 2003/4/2
*
*
================================================================*/