?? 編程修養(yǎng)(四).txt
字號(hào):
11、出錯(cuò)信息的處理
—————————
你會(huì)處理出錯(cuò)信息嗎?哦,它并不是簡單的輸出。看下面的示例:
if ( p == NULL ){
printf ( "ERR: The pointer is NULL\n" );
}
告別學(xué)生時(shí)代的編程吧。這種編程很不利于維護(hù)和管理,出錯(cuò)信息或是提示信息,應(yīng)該統(tǒng)
一處理,而不是像上面這樣,寫成一個(gè)“硬編碼”。第10條對這方面的處理做了一部分說
明。如果要管理錯(cuò)誤信息,那就要有以下的處理:
/* 聲明出錯(cuò)代碼 */
#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 */
/* 聲明出錯(cuò)信息 */
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",
/* 10 */ "Communication time out",
};
/* 聲明錯(cuò)誤代碼全局變量 */
long errno = 0;
/* 打印出錯(cuò)信息函數(shù) */
void perror( char* info)
{
if ( info ){
printf("%s: %s\n", info, errmsg[errno] );
return;
}
printf("Error: %s\n", errmsg[errno] );
}
這個(gè)基本上是ANSI的錯(cuò)誤處理實(shí)現(xiàn)細(xì)節(jié)了,于是當(dāng)你程序中有錯(cuò)誤時(shí)你就可以這樣處理:
bool CheckPermission( char* userName )
{
if ( strcpy(userName, "root") != 0 ){
errno = ERR_PERMISSION_DENIED;
return (FALSE);
}
...
}
main()
{
...
if (! CheckPermission( username ) ){
perror("main()");
}
...
}
一個(gè)即有共性,也有個(gè)性的錯(cuò)誤信息處理,這樣做有利同種錯(cuò)誤出一樣的信息,統(tǒng)一用戶
界面,而不會(huì)因?yàn)槲募蜷_失敗,A程序員出一個(gè)信息,B程序員又出一個(gè)信息。而且這樣
做,非常容易維護(hù)。代碼也易讀。
當(dāng)然,物極必反,也沒有必要把所有的輸出都放到errmsg中,抽取比較重要的出錯(cuò)信息或
是提示信息是其關(guān)鍵,但即使這樣,這也包括了大多數(shù)的信息。
12、常用函數(shù)和循環(huán)語句中的被計(jì)算量
—————————————————
看一下下面這個(gè)例子:
for( i=0; i<1000; i++ ){
GetLocalHostName( hostname );
...
}
GetLocalHostName的意思是取得當(dāng)前計(jì)算機(jī)名,在循環(huán)體中,它會(huì)被調(diào)用1000次啊。這是
多么的沒有效率的事啊。應(yīng)該把這個(gè)函數(shù)拿到循環(huán)體外,這樣只調(diào)用一次,效率得到了很
大的提高。雖然,我們的編譯器會(huì)進(jìn)行優(yōu)化,會(huì)把循環(huán)體內(nèi)的不變的東西拿到循環(huán)外面,
但是,你相信所有編譯器會(huì)知道哪些是不變的嗎?我覺得編譯器不可靠。最好還是自己動(dòng)
手吧。
同樣,對于常用函數(shù)中的不變量,如:
GetLocalHostName(char* name)
{
{
char funcName[] = "GetLocalHostName";
sys_log( "%s begin......", funcName );
...
sys_log( "%s end......", funcName );
}
如果這是一個(gè)經(jīng)常調(diào)用的函數(shù),每次調(diào)用時(shí)都要對funcName進(jìn)行分配內(nèi)存,這個(gè)開銷很大
啊。把這個(gè)變量聲明成static吧,當(dāng)函數(shù)再次被調(diào)用時(shí),就會(huì)省去了分配內(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)一加一個(gè)前綴或是后綴,讓人一看到這個(gè)變量就知道是全局的。
7) 用匈牙利命名法命名函數(shù)參數(shù),局部變量。但還是要堅(jiān)持“望文生意”的原則。
8) 與標(biāo)準(zhǔn)庫(如:STL)或開發(fā)庫(如:MFC)的命名風(fēng)格保持一致。
14、函數(shù)的傳值和傳指針
————————————
向函數(shù)傳參數(shù)時(shí),一般而言,傳入非const的指針時(shí),就表示,在函數(shù)中要修改這個(gè)指針把
指內(nèi)存中的數(shù)據(jù)。如果是傳值,那么無論在函數(shù)內(nèi)部怎么修改這個(gè)值,也影響不到傳過來
的值,因?yàn)閭髦凳侵粌?nèi)存拷貝。
什么?你說這個(gè)特性你明白了,好吧,讓我們看看下面的這個(gè)例程:
void
void
GetVersion(char* pStr)
{
pStr = malloc(10);
strcpy ( pStr, "2.0" );
}
main()
{
char* ver = NULL;
GetVersion ( ver );
...
...
free ( ver );
}
我保證,類似這樣的問題是一個(gè)新手最容易犯的錯(cuò)誤。程序中妄圖通過函數(shù)GetVersion給
指針ver分配空間,但這種方法根本沒有什么作用,原因就是——這是傳值,不是傳指針。
你或許會(huì)和我爭論,我分明傳的時(shí)指針啊?再仔細(xì)看看,其實(shí),你傳的是指針其實(shí)是在傳
值。
15、修改別人程序的修養(yǎng)
———————————
當(dāng)你維護(hù)別人的程序時(shí),請不要非常主觀臆斷的把已有的程序刪除或是修改。我經(jīng)常看到
有的程序員直接在別人的程序上修改表達(dá)式或是語句。修改別人的程序時(shí),請不要?jiǎng)h除別
人的程序,如果你覺得別人的程序有所不妥,請注釋掉,然后添加自己的處理程序,必竟
,你不可能100%的知道別人的意圖,所以為了可以恢復(fù),請不依賴于CVS或是SourceSafe這
種版本控制軟件,還是要在源碼上給別人看到你修改程序的意圖和步驟。這是程序維護(hù)時(shí)
,一個(gè)有修養(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 );
/* ---------------------------------------- */
* char* p = 開始使勁) malloc( 10 );
* memset( p, 0, 10 );
*/
/* ------ Added by haoel 2003/04/12 ----- */
char* p = ( char* )calloc( 10, sizeof char );
/* ---------------------------------------- */
...
當(dāng)然,這種方法是在軟件維護(hù)時(shí)使用的,這樣的方法,可以讓再維護(hù)的人很容易知道以前
的代碼更改的動(dòng)作和意圖,而且這也是對原作者的一種尊敬。
以“注釋 — 添加”方式修改別人的程序,要好于直接刪除別人的程序。
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -