编程修养(四)
11、出錯信息的處理
—————————
你會處理出錯信息嗎?哦,它并不是簡單的輸出。看下面的示例: if ( p == NULL ){
??????? printf ( "ERR: The pointer is NULL\n" );
??? }
????
告別學(xué)生時代的編程吧。這種編程很不利于維護(hù)和管理,出錯信息或是提示信息,應(yīng)該統(tǒng)一處理,而不是像上面這樣,寫成一個“硬編碼”。第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_PERMISSION ?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;
????
??? /* 打印出錯信息函數(shù) */
??? void perror( char* info)
??? {
??????? if ( info ){
??????????? printf("%s: %s\n", info, errmsg[errno] );
??????????? return;
??????? }
????????
??????? printf("Error: %s\n", errmsg[errno] );
??? } 這個基本上是ANSI的錯誤處理實現(xiàn)細(xì)節(jié)了,于是當(dāng)你程序中有錯誤時你就可以這樣處理: bool CheckPermission( char* userName )
??? {
??????? if ( strcpy(userName, "root") != 0 ){
??????????? errno = ERR_PERMISSION_DENIED;
??????????? return (FALSE);
??????? }
????????
??????? ...
??? }
????
??? main()
??? {
??????? ...
??????? if (! CheckPermission( username ) ){
??????????? perror("main()");
??????? }
??????? ...
??? }
??????????????????????????????
一個即有共性,也有個性的錯誤信息處理,這樣做有利同種錯誤出一樣的信息,統(tǒng)一用戶界面,而不會因為文件打開失敗,A程序員出一個信息,B程序員又出一個信息。而且這樣做,非常容易維護(hù)。代碼也易讀。 當(dāng)然,物極必反,也沒有必要把所有的輸出都放到errmsg中,抽取比較重要的出錯信息或是提示信息是其關(guān)鍵,但即使這樣,這也包括了大多數(shù)的信息。
12、常用函數(shù)和循環(huán)語句中的被計算量
—————————————————
看一下下面這個例子: for( i=0; i<1000; i++ ){
??????? GetLocalHostName( hostname );
??????? ...
??? }
????
GetLocalHostName的意思是取得當(dāng)前計算機(jī)名,在循環(huán)體中,它會被調(diào)用1000次啊。這是多么的沒有效率的事啊。應(yīng)該把這個函數(shù)拿到循環(huán)體外,這樣只調(diào)用一次,效率得到了很大的提高。雖然,我們的編譯器會進(jìn)行優(yōu)化,會把循環(huán)體內(nèi)的不變的東西拿到循環(huán)外面,但是,你相信所有編譯器會知道哪些是不變的嗎?我覺得編譯器不可靠。最好還是自己動手吧。 同樣,對于常用函數(shù)中的不變量,如: GetLocalHostName(char* name)
{
??? char funcName[] = "GetLocalHostName";
????
??? sys_log( "%s begin......", funcName );
??? ...
??? sys_log( "%s end......", funcName );
} 如果這是一個經(jīng)常調(diào)用的函數(shù),每次調(diào)用時都要對funcName進(jìn)行分配內(nèi)存,這個開銷很大啊。把這個變量聲明成static吧,當(dāng)函數(shù)再次被調(diào)用時,就會省去了分配內(nèi)存的開銷,執(zhí)行效率也很好。
??? 13、函數(shù)名和變量名的命名
————————————
我看到許多程序?qū)ψ兞棵秃瘮?shù)名的取名很草率,特別是變量名,什么a,b,c,aa,bb,cc,還有什么flag1,flag2, cnt1, cnt2,這同樣是一種沒有“修養(yǎng)”的行為。即便加上好的注釋。好的變量名或是函數(shù)名,我認(rèn)為應(yīng)該有以下的規(guī)則:
????
??? 1) 直觀并且可以拼讀,可望文知意,不必“解碼”。?
??? 2) 名字的長度應(yīng)該即要最短的長度,也要能最大限度的表達(dá)其含義。
??? 3) 不要全部大寫,也不要全部小寫,應(yīng)該大小寫都有,如:GetLocalHostName 或是 UserAccount。
??? 4) 可以簡寫,但簡寫得要讓人明白,如:ErrorCode -> ErrCode,? ServerListener -> ServLisner,UserAccount -> UsrAcct 等。
??? 5) 為了避免全局函數(shù)和變量名字沖突,可以加上一些前綴,一般以模塊簡稱做為前綴。
??? 6) 全局變量統(tǒng)一加一個前綴或是后綴,讓人一看到這個變量就知道是全局的。
??? 7) 用匈牙利命名法命名函數(shù)參數(shù),局部變量。但還是要堅持“望文生意”的原則。
??? 8) 與標(biāo)準(zhǔn)庫(如:STL)或開發(fā)庫(如:MFC)的命名風(fēng)格保持一致。
???
14、函數(shù)的傳值和傳指針
————————————
向函數(shù)傳參數(shù)時,一般而言,傳入非const的指針時,就表示,在函數(shù)中要修改這個指針把指內(nèi)存中的數(shù)據(jù)。如果是傳值,那么無論在函數(shù)內(nèi)部怎么修改這個值,也影響不到傳過來的值,因為傳值是只內(nèi)存拷貝。 什么?你說這個特性你明白了,好吧,讓我們看看下面的這個例程: void
GetVersion(char* pStr)
{
??? pStr = malloc(10);
??? strcpy ( pStr, "2.0" );
} main()
{
??? char* ver = NULL;
??? GetVersion ( ver );
??? ...
??? ...
??? free ( ver );
} 我保證,類似這樣的問題是一個新手最容易犯的錯誤。程序中妄圖通過函數(shù)GetVersion給指針ver分配空間,但這種方法根本沒有什么作用,原因就是——這是傳值,不是傳指針。你或許會和我爭論,我分明傳的時指針啊?再仔細(xì)看看,其實,你傳的是指針其實是在傳值。 15、修改別人程序的修養(yǎng)
——————————— 當(dāng)你維護(hù)別人的程序時,請不要非常主觀臆斷的把已有的程序刪除或是修改。我經(jīng)常看到有的程序員直接在別人的程序上修改表達(dá)式或是語句。修改別人的程序時,請不要刪除別人的程序,如果你覺得別人的程序有所不妥,請注釋掉,然后添加自己的處理程序,必竟,你不可能100%的知道別人的意圖,所以為了可以恢復(fù),請不依賴于CVS或是SourceSafe這種版本控制軟件,還是要在源碼上給別人看到你修改程序的意圖和步驟。這是程序維護(hù)時,一個有修養(yǎng)的程序員所應(yīng)該做的。 如下所示,這就是一種比較好的修改方法: /*
???? * ----- commented by haoel 2003/04/12 ------
???? *
???? *?? char* p = ( char* ) malloc( 10 );
???? *?? memset( p, 0, 10 );
???? */
?????
??? /* ------ Added by haoel?? 2003/04/12 ----- */
???? char* p = ( char* )calloc( 10, sizeof char );
??? /* ---------------------------------------- */
??? ... 當(dāng)然,這種方法是在軟件維護(hù)時使用的,這樣的方法,可以讓再維護(hù)的人很容易知道以前的代碼更改的動作和意圖,而且這也是對原作者的一種尊敬。 以“注釋 — 添加”方式修改別人的程序,要好于直接刪除別人的程序。
本文轉(zhuǎn)自 haoel 51CTO博客,原文鏈接:http://blog.51cto.com/haoel/124710,如需轉(zhuǎn)載請自行聯(lián)系原作者
—————————
你會處理出錯信息嗎?哦,它并不是簡單的輸出。看下面的示例: if ( p == NULL ){
??????? printf ( "ERR: The pointer is NULL\n" );
??? }
????
告別學(xué)生時代的編程吧。這種編程很不利于維護(hù)和管理,出錯信息或是提示信息,應(yīng)該統(tǒng)一處理,而不是像上面這樣,寫成一個“硬編碼”。第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_PERMISSION ?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;
????
??? /* 打印出錯信息函數(shù) */
??? void perror( char* info)
??? {
??????? if ( info ){
??????????? printf("%s: %s\n", info, errmsg[errno] );
??????????? return;
??????? }
????????
??????? printf("Error: %s\n", errmsg[errno] );
??? } 這個基本上是ANSI的錯誤處理實現(xiàn)細(xì)節(jié)了,于是當(dāng)你程序中有錯誤時你就可以這樣處理: bool CheckPermission( char* userName )
??? {
??????? if ( strcpy(userName, "root") != 0 ){
??????????? errno = ERR_PERMISSION_DENIED;
??????????? return (FALSE);
??????? }
????????
??????? ...
??? }
????
??? main()
??? {
??????? ...
??????? if (! CheckPermission( username ) ){
??????????? perror("main()");
??????? }
??????? ...
??? }
??????????????????????????????
一個即有共性,也有個性的錯誤信息處理,這樣做有利同種錯誤出一樣的信息,統(tǒng)一用戶界面,而不會因為文件打開失敗,A程序員出一個信息,B程序員又出一個信息。而且這樣做,非常容易維護(hù)。代碼也易讀。 當(dāng)然,物極必反,也沒有必要把所有的輸出都放到errmsg中,抽取比較重要的出錯信息或是提示信息是其關(guān)鍵,但即使這樣,這也包括了大多數(shù)的信息。
12、常用函數(shù)和循環(huán)語句中的被計算量
—————————————————
看一下下面這個例子: for( i=0; i<1000; i++ ){
??????? GetLocalHostName( hostname );
??????? ...
??? }
????
GetLocalHostName的意思是取得當(dāng)前計算機(jī)名,在循環(huán)體中,它會被調(diào)用1000次啊。這是多么的沒有效率的事啊。應(yīng)該把這個函數(shù)拿到循環(huán)體外,這樣只調(diào)用一次,效率得到了很大的提高。雖然,我們的編譯器會進(jìn)行優(yōu)化,會把循環(huán)體內(nèi)的不變的東西拿到循環(huán)外面,但是,你相信所有編譯器會知道哪些是不變的嗎?我覺得編譯器不可靠。最好還是自己動手吧。 同樣,對于常用函數(shù)中的不變量,如: GetLocalHostName(char* name)
{
??? char funcName[] = "GetLocalHostName";
????
??? sys_log( "%s begin......", funcName );
??? ...
??? sys_log( "%s end......", funcName );
} 如果這是一個經(jīng)常調(diào)用的函數(shù),每次調(diào)用時都要對funcName進(jìn)行分配內(nèi)存,這個開銷很大啊。把這個變量聲明成static吧,當(dāng)函數(shù)再次被調(diào)用時,就會省去了分配內(nèi)存的開銷,執(zhí)行效率也很好。
??? 13、函數(shù)名和變量名的命名
————————————
我看到許多程序?qū)ψ兞棵秃瘮?shù)名的取名很草率,特別是變量名,什么a,b,c,aa,bb,cc,還有什么flag1,flag2, cnt1, cnt2,這同樣是一種沒有“修養(yǎng)”的行為。即便加上好的注釋。好的變量名或是函數(shù)名,我認(rèn)為應(yīng)該有以下的規(guī)則:
????
??? 1) 直觀并且可以拼讀,可望文知意,不必“解碼”。?
??? 2) 名字的長度應(yīng)該即要最短的長度,也要能最大限度的表達(dá)其含義。
??? 3) 不要全部大寫,也不要全部小寫,應(yīng)該大小寫都有,如:GetLocalHostName 或是 UserAccount。
??? 4) 可以簡寫,但簡寫得要讓人明白,如:ErrorCode -> ErrCode,? ServerListener -> ServLisner,UserAccount -> UsrAcct 等。
??? 5) 為了避免全局函數(shù)和變量名字沖突,可以加上一些前綴,一般以模塊簡稱做為前綴。
??? 6) 全局變量統(tǒng)一加一個前綴或是后綴,讓人一看到這個變量就知道是全局的。
??? 7) 用匈牙利命名法命名函數(shù)參數(shù),局部變量。但還是要堅持“望文生意”的原則。
??? 8) 與標(biāo)準(zhǔn)庫(如:STL)或開發(fā)庫(如:MFC)的命名風(fēng)格保持一致。
???
14、函數(shù)的傳值和傳指針
————————————
向函數(shù)傳參數(shù)時,一般而言,傳入非const的指針時,就表示,在函數(shù)中要修改這個指針把指內(nèi)存中的數(shù)據(jù)。如果是傳值,那么無論在函數(shù)內(nèi)部怎么修改這個值,也影響不到傳過來的值,因為傳值是只內(nèi)存拷貝。 什么?你說這個特性你明白了,好吧,讓我們看看下面的這個例程: void
GetVersion(char* pStr)
{
??? pStr = malloc(10);
??? strcpy ( pStr, "2.0" );
} main()
{
??? char* ver = NULL;
??? GetVersion ( ver );
??? ...
??? ...
??? free ( ver );
} 我保證,類似這樣的問題是一個新手最容易犯的錯誤。程序中妄圖通過函數(shù)GetVersion給指針ver分配空間,但這種方法根本沒有什么作用,原因就是——這是傳值,不是傳指針。你或許會和我爭論,我分明傳的時指針啊?再仔細(xì)看看,其實,你傳的是指針其實是在傳值。 15、修改別人程序的修養(yǎng)
——————————— 當(dāng)你維護(hù)別人的程序時,請不要非常主觀臆斷的把已有的程序刪除或是修改。我經(jīng)常看到有的程序員直接在別人的程序上修改表達(dá)式或是語句。修改別人的程序時,請不要刪除別人的程序,如果你覺得別人的程序有所不妥,請注釋掉,然后添加自己的處理程序,必竟,你不可能100%的知道別人的意圖,所以為了可以恢復(fù),請不依賴于CVS或是SourceSafe這種版本控制軟件,還是要在源碼上給別人看到你修改程序的意圖和步驟。這是程序維護(hù)時,一個有修養(yǎng)的程序員所應(yīng)該做的。 如下所示,這就是一種比較好的修改方法: /*
???? * ----- commented by haoel 2003/04/12 ------
???? *
???? *?? char* p = ( char* ) malloc( 10 );
???? *?? memset( p, 0, 10 );
???? */
?????
??? /* ------ Added by haoel?? 2003/04/12 ----- */
???? char* p = ( char* )calloc( 10, sizeof char );
??? /* ---------------------------------------- */
??? ... 當(dāng)然,這種方法是在軟件維護(hù)時使用的,這樣的方法,可以讓再維護(hù)的人很容易知道以前的代碼更改的動作和意圖,而且這也是對原作者的一種尊敬。 以“注釋 — 添加”方式修改別人的程序,要好于直接刪除別人的程序。
本文轉(zhuǎn)自 haoel 51CTO博客,原文鏈接:http://blog.51cto.com/haoel/124710,如需轉(zhuǎn)載請自行聯(lián)系原作者
總結(jié)
- 上一篇: 使用注解实现ssh整合
- 下一篇: RMAN删除归档日志不释放问题