程式設計修養(四) (轉)
11、出錯資訊的處理
—————————
你會處理出錯資訊嗎?哦,它並不是簡單的輸出。看下面的示例:
if ( p == NULL ){
printf ( "ERR: The pointer is NULL
" );
}
告別學生時代的吧。這種程式設計很不利於維護和管理,出錯資訊或是提示資訊,應該統一處理,而不是像上面這樣,寫成一個“硬編碼”。第10條對這方面的處理做了一部分說明。如果要管理錯誤資訊,那就要有以下的處理:
/* 宣告出錯程式碼 */
#define ERR_NO_ERROR 0 /* No error */
#define ERR_OPEN_FILE 1 /* Open file error */
#define ERR_SEND_MESG 2 /* sending a message error */
#define ERR_BAD_ARGS 3 /* Bad arguments */
#define ERR_MEM_NONE 4 /* Memeroy is not enough */
#define ERR_SERV_DOWN 5 /* Service down try later */
#define ERR_UNKNOW_INFO 6 /* Unknow information */
#define ERR_SOCKET_ERR 7 /* Socket operation failed */
#define ERR_PESSION 8 /* Permission denied */
#define ERR_BAD_FORMAT 9 /* Bad configuration file */
#define ERR_TIME_OUT 10 /* Communication time out */
/* 宣告出錯資訊 */
char* errmsg[] = {
/* 0 */ "No error",
/* 1 */ "Open file error",
/* 2 */ "Failed in sending/receiving a message",
/* 3 */ "Bad arguments",
/* 4 */ "Memeroy is not enough",
/* 5 */ "Service is down; try later",
/* 6 */ "Unknow information",
/* 7 */ "A socket operation has failed",
/* 8 */ "Permission denied",
/* 9 */ "Bad configuration file format",
/* 10 */ "Communication time out",
};
/* 宣告錯誤程式碼全域性變數 */
long errno = 0;
/* 列印出錯資訊 */
void perror( char* info)
{
if ( info ){
printf("%s: %s
", info, errmsg[errno] );
return;
}
printf("Error: %s
", errmsg[errno] );
}
這個基本上是ANSI的錯誤處理實現細節了,於是當你中有錯誤時你就可以這樣處理:
bool CheckPermission( char* userName )
{
if ( strcpy(userName, "") != 0 ){
errno = ERR_PERMISSION_DENIED;
return (FALSE);
}
...
}
main()
{
...
if (! CheckPermission( username ) ){
perror("main()");
}
...
}
一個即有共性,也有個性的錯誤資訊處理,這樣做有利同種錯誤出一樣的資訊,統一介面,而不會因為開啟失敗,A程式設計師出一個資訊,B程式設計師又出一個資訊。而且這樣做,非常容易維護。程式碼也易讀。
當然,物極必反,也沒有必要把所有的輸出都放到errmsg中,抽取比較重要的出錯資訊或是提示資訊是其關鍵,但即使這樣,這也包括了大多數的資訊。
12、常用函式和迴圈語句中的被計算量
—————————————————
看一下下面這個例子:
for( i=0; i<1000; i++ ){
GetLocalHostName( hostname );
...
}
GetLocalHostName的意思是取得當前名,在迴圈體中,它會被1000次啊。這是多麼的沒有的事啊。應該把這個函式拿到迴圈體外,這樣只呼叫一次,效率得到了很大的提高。雖然,我們的會進行,會把迴圈體內的不變的東西拿到迴圈外面,但是,你相信所有編譯器會知道哪些是不變的嗎?我覺得編譯器不可靠。最好還是自己動手吧。
同樣,對於常用函式中的不變數,如:
GetLocalHostName(char* name)
{
char funcName[] = "GetLocalHostName";
sys_log( "%s begin......", funcName );
...
sys_log( "%s end......", funcName );
}
如果這是一個經常呼叫的函式,每次呼叫時都要對funcName進行分配,這個開銷很大啊。把這個變數宣告成static吧,當函式再次被呼叫時,就會省去了分配記憶體的開銷,效率也很好。
13、函式名和變數名的命名
————————————
我看到許多程式對變數名和函式名的取名很草率,特別是變數名,什麼a,b,c,aa,bb,cc,還有什麼flag1,flag2, cnt1, cnt2,這同樣是一種沒有“修養”的行為。即便加上好的註釋。好的變數名或是函式名,我認為應該有以下的規則:
1) 直觀並且可以拼讀,可望文知意,不必“解碼”。
2) 名字的長度應該即要最短的長度,也要能最大限度的表達其含義。
3) 不要全部大寫,也不要全部小寫,應該大小寫都有,如:GetLocalHostName 或是 UserAccount。
4) 可以簡寫,但簡寫得要讓人明白,如:ErrorCode -> ErrCode, ServerListener -> ServLisner,UserAccount -> UsrAcct 等。
5) 為了避免全域性函式和變數名字衝突,可以加上一些字首,一般以模組簡稱做為字首。
6) 全域性變數統一加一個字首或是字尾,讓人一看到這個變數就知道是全域性的。
7) 用匈牙利命名法命名函式引數,區域性變數。但還是要堅持“望文生意”的原則。
8) 與標準庫(如:STL)或開發庫(如:MFC)的命名風格保持一致。
14、函式的傳值和傳指標
————————————
向函式傳引數時,一般而言,傳入非const的指標時,就表示,在函式中要修改這個指標把指記憶體中的資料。如果是傳值,那麼無論在函式內部怎麼修改這個值,也影響不到傳過來的值,因為傳值是隻記憶體複製。
什麼?你說這個特性你明白了,好吧,讓我們看看下面的這個例程:
void
GetVersion(char* pStr)
{
pStr = malloc(10);
strcpy ( pStr, "2.0" );
}
main()
{
char* ver = NULL;
GetVersion ( ver );
...
...
free ( ver );
}
我保證,類似這樣的問題是一個新手最容易犯的錯誤。程式中妄圖透過函式GetVersion給指標ver分配空間,但這種方法根本沒有什麼作用,原因就是——這是傳值,不是傳指標。你或許會和我爭論,我分明傳的時指標啊?再仔細看看,其實,你傳的是指標其實是在傳值。
15、修改別人程式的修養
———————————
當你維護別人的程式時,請不要非常主觀臆斷的把已有的程式刪除或是修改。我經常看到有的程式設計師直接在別人的程式上修改或是語句。修改別人的程式時,請不要刪除別人的程式,如果你覺得別人的程式有所不妥,請註釋掉,然後新增自己的處理程式,必竟,你不可能100%的知道別人的意圖,所以為了可以恢復,請不依賴於或是Safe這種版本控制,還是要在原始碼上給別人看到你修改程式的意圖和步驟。這是程式維護時,一個有修養的程式設計師所應該做的。
如下所示,這就是一種比較好的修改方法:
/*
* ----- commented by haoel /04/12 ------
*
* char* p = ( char* ) malloc( 10 );
* memset( p, 0, 10 );
*/
/* ------ Added by haoel 2003/04/12 ----- */
char* p = ( char* )calloc( 10, sizeof char );
/* ---------------------------------------- */
...
當然,這種方法是在軟體維護時使用的,這樣的方法,可以讓再維護的人很容易知道以前的程式碼更改的動作和意圖,而且這也是對原作者的一種尊敬。
以“註釋 — 新增”方式修改別人的程式,要好於直接刪除別人的程式。
/Develop/read_article.?id=18271">
(版權所有,轉載時請註明出處和作者資訊)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-956447/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 程式設計師的科技道德修養 - idlewords程式設計師
- 程式設計師修煉之道~四程式設計師
- 《程式設計師自我修養》讀書筆記程式設計師筆記
- 一個野生程式設計師的自我修養程式設計師
- 程式設計師的自我修養-編譯連結程式設計師編譯
- 《程式設計師的自我修養》-讀書筆記程式設計師筆記
- 程式設計師的自我修養筆記之裝載程式設計師筆記
- 從程式設計到養生程式設計程式設計
- 很認真的談一談程式設計師的自我修養程式設計師
- 《程式設計師的自我修養》(三)——庫與執行庫程式設計師
- 《程式設計師的自我修養筆記之靜態連結》程式設計師筆記
- 養生吧,程式設計師!程式設計師
- 切圖崽的自我修養-[ES6] 程式設計風格規範程式設計
- java從零開始系列-一個前端程式設計師的自我修養Java前端程式設計師
- 遊戲設計師的自我修養(三):理解玩家遊戲設計師
- @程式設計師,再不養生就晚了程式設計師
- 四、GO程式設計模式:委託和反轉控制Go程式設計設計模式
- GitHub 熱點速覽 Vol.28:有品位程式設計師的自我修養Github程式設計師
- 《程式設計師的自我修養》筆記(二)——裝載與動態連結程式設計師筆記
- MFC程式設計(四)C程式程式設計
- 程式設計師“求包養”攻略揭秘程式設計師
- 程式設計師修煉之道程式設計師
- 併發程式設計(四)程式設計
- 程式設計師的職業素養(一)程式設計師
- 如何培養良好的程式設計實踐程式設計
- 如何培養良好的程式設計風格程式設計
- 接客周·程式設計養生·帶薪休假與菊部養生程式設計
- 《程式設計師修煉之道:從小工到專家》讀書筆記(四)程式設計師筆記
- 程式設計師修煉之道6程式設計師
- 程式設計師修煉之道7程式設計師
- 程式設計師修煉之道~三程式設計師
- 程式設計師修煉之道~五程式設計師
- 程式設計師修煉之道2程式設計師
- 程式設計師修煉之道1程式設計師
- 程式設計師修煉之道3程式設計師
- 遊戲設計師的自我修養(一):認識玩家,理解玩家遊戲設計師
- 遊戲設計師的自我修養(一):認識玩家、理解玩家遊戲設計師
- cuda程式設計與gpu平行計算(四):cuda程式設計模型程式設計GPU模型
- 玩轉 PHP 網路程式設計全套之多程式程式設計PHP程式設計