?? 編程修養(yǎng)(七).txt
字號(hào):
28、||和&&的語句執(zhí)行順序
————————————
條件語句中的這兩個(gè)“與”和“或”操作符一定要小心,它們的表現(xiàn)可能和你想像的不一
樣,這里條件語句中的有些行為需要和說一下:
express1 || express2
先執(zhí)行表達(dá)式express1如果為“真”,express2將不被執(zhí)行,express2僅在express1
為“假”時(shí)才被執(zhí)行。因?yàn)榈谝粋€(gè)表達(dá)式為真了,整個(gè)表達(dá)式都為真,所以沒有必要再去
執(zhí)行第二個(gè)表達(dá)式了。
express1 && express2
先執(zhí)行表達(dá)式express1如果為“假”,express2將不被執(zhí)行,express2僅在express1
為“真”時(shí)才被執(zhí)行。因?yàn)榈谝粋€(gè)表達(dá)式為假了,整個(gè)表達(dá)式都為假了,所以沒有必要再
去執(zhí)行第二個(gè)表達(dá)式了。
于是,他并不是你所想像的所有的表達(dá)式都會(huì)去執(zhí)行,這點(diǎn)一定要明白,不然你的程序會(huì)
出現(xiàn)一些莫明的運(yùn)行時(shí)錯(cuò)誤。
例如,下面的程序:
if ( sum > 100 &&
( ( fp=fopen( filename,"a" ) ) != NULL ) {
fprintf(fp, "Warring: it beyond one hundred\n");
......
}
fprintf( fp, " sum is %id \n", sum );
fclose( fp );
本來的意圖是,如果sum > 100 ,向文件中寫一條出錯(cuò)信息,為了方便,把兩個(gè)條件判斷
寫在一起,于是,如果sum<=100時(shí),打開文件的操作將不會(huì)做,最后,fprintf和fclose就
會(huì)發(fā)現(xiàn)未知的結(jié)果。
再比如,如果我想判斷一個(gè)字符是不是有內(nèi)容,我得判斷這個(gè)字符串指針是不為空(NULL
)并且其內(nèi)容不能為空(Empty),一個(gè)是空指針,一個(gè)是空內(nèi)容。我也許會(huì)這樣寫:
if ( ( p != NULL ) && ( strlen(p) != 0 ))
于是,如果p為NULL,那么strlen(p)就不會(huì)被執(zhí)行,于是,strlen也就不會(huì)因?yàn)橐粋€(gè)空指
針而“非法操作”或是一個(gè)“Core Dump”了。
記住一點(diǎn),條件語句中,并非所有的語句都會(huì)執(zhí)行,當(dāng)你的條件語句非常多時(shí),這點(diǎn)要尤
其注意。
29、盡量用for而不是while做循環(huán)
———————————————
基本上來說,for可以完成while的功能,我是建議盡量使用for語句,而不要使用while語
句,特別是當(dāng)循環(huán)體很大時(shí),for的優(yōu)點(diǎn)一下就體現(xiàn)出來了。
因?yàn)樵趂or中,循環(huán)的初始、結(jié)束條件、循環(huán)的推進(jìn),都在一起,一眼看上去就知道這是一
個(gè)什么樣的循環(huán)。剛出學(xué)校的程序一般對(duì)于鏈接喜歡這樣來:
p = pHead;
p = pHead;
while ( p ){
...
...
p = p->next;
}
當(dāng)while的語句塊變大后,你的程序?qū)⒑茈y讀,用for就好得多:
for ( p=pHead; p; p=p->next ){
..
}
一眼就知道這個(gè)循環(huán)的開始條件,結(jié)束條件,和循環(huán)的推進(jìn)。大約就能明白這個(gè)循環(huán)要做
個(gè)什么事?而且,程序維護(hù)進(jìn)來很容易,不必像while一樣,在一個(gè)編輯器中上上下下的搗
騰。
30、請(qǐng)sizeof類型而不是變量
—————————————
許多程序員在使用sizeof中,喜歡sizeof變量名,例如:
int score[100];
char filename[20];
struct UserInfo usr[100];
在sizeof這三個(gè)的變量名時(shí),都會(huì)返回正確的結(jié)果,于是許多程序員就開始sizeof變量名
。這個(gè)習(xí)慣很雖然沒有什么不好,但我還是建議sizeof類型。
我看到過這個(gè)的程序:
pScore = (int*) malloc( SUBJECT_CNT );
memset( pScore, 0, sizeof(pScore) );
...
此時(shí),sizeof(pScore)返回的就是4(指針的長(zhǎng)度),不會(huì)是整個(gè)數(shù)組,于是,memset就不
能對(duì)這塊內(nèi)存進(jìn)行初始化。為了程序的易讀和易維護(hù),我強(qiáng)烈建議使用類型而不是變量,
如:
對(duì)于score: sizeof(int) * 100 /* 100個(gè)int */
對(duì)于filename: sizeof(char) * 20 /* 20個(gè)char */
對(duì)于usr: sizeof(struct UserInfo) * 100 /* 100個(gè)UserInfo */
這樣的代碼是不是很易讀?一眼看上去就知道什么意思了。
另外一點(diǎn),sizeof一般用于分配內(nèi)存,這個(gè)特性特別在多維數(shù)組時(shí),就能體現(xiàn)出其優(yōu)點(diǎn)了
。如,給一個(gè)字符串?dāng)?shù)組分配內(nèi)存,
/*
* 分配一個(gè)有20個(gè)字符串,
* 每個(gè)字符串長(zhǎng)100的內(nèi)存
*/
char* *p;
/*
* 錯(cuò)誤的分配方法
*/
p = (char**)calloc( 20*100, sizeof(char) );
/*
* 正確的分配方法
* 正確的分配方法
*/
p = (char**) calloc ( 20, sizeof(char*) );
for ( i=0; i<20; i++){
/*p = (char*) calloc ( 100, sizeof(char) );*/
p[i] = (char*) calloc ( 100, sizeof(char) );
}
(注:上述語句被注釋掉的是原來的,是錯(cuò)誤的,由dasherest朋友指正,謝謝)
為了代碼的易讀,省去了一些判斷,請(qǐng)注意這兩種分配的方法,有本質(zhì)上的差別。
31、不要忽略Warning
——————————
對(duì)于一些編譯時(shí)的警告信息,請(qǐng)不要忽視它們。雖然,這些Warning不會(huì)妨礙目標(biāo)代碼的生
成,但這并不意味著你的程序就是好的。必竟,并不是編譯成功的程序才是正確的,編譯
成功只是萬里長(zhǎng)征的第一步,后面還有大風(fēng)大浪在等著你。從編譯程序開始,不但要改正
每個(gè)error,還要修正每個(gè)warning。這是一個(gè)有修養(yǎng)的程序員該做的事。
一般來說,一面的一些警告信息是常見的:
1)聲明了未使用的變量。(雖然編譯器不會(huì)編譯這種變量,但還是把它從源程序中注
釋或是刪除吧)
2)使用了隱晦聲明的函數(shù)。(也許這個(gè)函數(shù)在別的C文件中,編譯時(shí)會(huì)出現(xiàn)這種警告
,你應(yīng)該這使用之前使用extern關(guān)鍵字聲明這個(gè)函數(shù))
3)沒有轉(zhuǎn)換一個(gè)指針。(例如malloc返回的指針是void的,你沒有把之轉(zhuǎn)成你實(shí)際類
型而報(bào)警,還是手動(dòng)的在之前明顯的轉(zhuǎn)換一下吧)
4)類型向下轉(zhuǎn)換。(例如:float f = 2.0; 這種語句是會(huì)報(bào)警告的,編譯會(huì)告訴你
正試圖把一個(gè)double轉(zhuǎn)成float,你正在閹割一個(gè)變量,你真的要這樣做嗎?還是在2.0后
面加個(gè)f吧,不然,2.0就是一個(gè)double,而不是float了)
不管怎么說,編譯器的Warning不要小視,最好不要忽略,一個(gè)程序都做得出來,何況幾個(gè)
小小的Warning呢?
32、書寫Debug版和Release版的程序
————————————————
程序在開發(fā)過程中必然有許多程序員加的調(diào)試信息。我見過許多項(xiàng)目組,當(dāng)程序開發(fā)結(jié)束
時(shí),發(fā)動(dòng)群眾刪除程序中的調(diào)試信息,何必呢?為什么不像VC++那樣建立兩個(gè)版本的目標(biāo)
代碼?一個(gè)是debug版本的,一個(gè)是Release版的。那些調(diào)試信息是那么的寶貴,在日后的
維護(hù)過程中也是很寶貴的東西,怎么能說刪除就刪除呢?
利用預(yù)編譯技術(shù)吧,如下所示聲明調(diào)試函數(shù):
#ifdef DEBUG
void TRACE(char* fmt, ...)
{
......
}
#else
#define TRACE(char* fmt, ...)
#endif
于是,讓所有的程序都用TRACE輸出調(diào)試信息,只需要在在編譯時(shí)加上一個(gè)參數(shù)“-DDEBUG
”,如:
cc -DDEBUG -o target target.c
于是,預(yù)編譯器發(fā)現(xiàn)DEBUG變量被定義了,就會(huì)使用TRACE函數(shù)。而如果要發(fā)布給用戶了,
那么只需要把取消“-DDEBUG”的參數(shù),于是所有用到TRACE宏,這個(gè)宏什么都沒有,所以
源程序中的所有TRACE語言全部被替換成了空。一舉兩得,一箭雙雕,何樂而不為呢?
順便提一下,兩個(gè)很有用的系統(tǒng)宏,一個(gè)是“__FILE__”,一個(gè)是“__LINE__”,分別表
示,所在的源文件和行號(hào),當(dāng)你調(diào)試信息或是輸出錯(cuò)誤時(shí),可以使用這兩個(gè)宏,讓你一眼
就能看出你的錯(cuò)誤,出現(xiàn)在哪個(gè)文件的第幾行中。這對(duì)于用C/C++做的大工程非常的管用。
綜上所述32條,都是為了三大目的——
2、程序代碼的可維護(hù)性,
3、程序代碼的穩(wěn)定可靠性。
的細(xì)小的問題,編程高手不僅技術(shù)要強(qiáng),基礎(chǔ)要好,而且最重要的是要有“修養(yǎng)”!
軟件的維護(hù)有大量的工作量花在代碼的維護(hù)上,軟件的Upgrade,也有大量的工作花在代碼
的組織上,所以好的代碼,清淅的,易讀的代碼,將給大大減少軟件的維護(hù)和升級(jí)成本。
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -