編程修養(四)

28、||和&&的語句執行順序
————————————
條件語句中的這兩個“與”和“或”操作符一定要小心,它們的表現可能和你想像的不一
樣,這裏條件語句中的有些行爲需要和說一下:
 
    express1 || express2
 
    先執行表達式express1如果爲“真”,express2將不被執行,express2僅在express1
爲“假”時才被執行。因爲第一個表達式爲真了,整個表達式都爲真,所以沒有必要再去
執行第二個表達式了。
 
    express1 && express2
 
    先執行表達式express1如果爲“假”,express2將不被執行,express2僅在express1
爲“真”時才被執行。因爲第一個表達式爲假了,整個表達式都爲假了,所以沒有必要再
去執行第二個表達式了。

 
 
於是,他並不是你所想像的所有的表達式都會去執行,這點一定要明白,不然你的程序會
出現一些莫明的運行時錯誤。
 
例如,下面的程序:
 
 
    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 ,向文件中寫一條出錯信息,爲了方便,把兩個條件判斷
寫在一起,於是,如果sum<=100時,打開文件的操作將不會做,最後,fprintf和fclose就
會發現未知的結果。
 
 
再比如,如果我想判斷一個字符是不是有內容,我得判斷這個字符串指針是不爲空(NULL
)並且其內容不能爲空(Empty),一個是空指針,一個是空內容。我也許會這樣寫:
 
    if ( ( p != NULL ) && ( strlen(p) != 0 ))
 
於是,如果p爲NULL,那麼strlen(p)就不會被執行,於是,strlen也就不會因爲一個空指
針而“非法操作”或是一個“Core Dump”了。
 
記住一點,條件語句中,並非所有的語句都會執行,當你的條件語句非常多時,這點要尤
其注意。
 
 
 
29、儘量用for而不是while做循環
———————————————
基本上來說,for可以完成while的功能,我是建議儘量使用for語句,而不要使用while語
句,特別是當循環體很大時,for的優點一下就體現出來了。
 
因爲在for中,循環的初始、結束條件、循環的推進,都在一起,一眼看上去就知道這是一
個什麼樣的循環。剛出學校的程序一般對於鏈接喜歡這樣來:
 
    p = pHead;
    p = pHead;
 
    while ( p ){
        ...
        ...
        p = p->next;
    }
 
當while的語句塊變大後,你的程序將很難讀,用for就好得多:
 
    for ( p=pHead;  p; p=p->next ){
    ..
    }
 
一眼就知道這個循環的開始條件,結束條件,和循環的推進。大約就能明白這個循環要做
個什麼事?而且,程序維護進來很容易,不必像while一樣,在一個編輯器中上上下下的搗
騰。
 
 
 
30、請sizeof類型而不是變量
—————————————
 
 
許多程序員在使用sizeof中,喜歡sizeof變量名,例如:
 
int score[100];
char filename[20];
struct UserInfo usr[100];
 
在sizeof這三個的變量名時,都會返回正確的結果,於是許多程序員就開始sizeof變量名
。這個習慣很雖然沒有什麼不好,但我還是建議sizeof類型。
 
我看到過這個的程序:
 
    pScore = (int*) malloc( SUBJECT_CNT );
    memset( pScore, 0, sizeof(pScore) );
    ...
 
此時,sizeof(pScore)返回的就是4(指針的長度),不會是整個數組,於是,memset就不
能對這塊內存進行初始化。爲了程序的易讀和易維護,我強烈建議使用類型而不是變量,
如:
 
對於score:     sizeof(int) * 100   /* 100個int */
對於filename:  sizeof(char) * 20   /* 20個char */
對於usr:       sizeof(struct UserInfo) * 100   /* 100個UserInfo */

 
這樣的代碼是不是很易讀?一眼看上去就知道什麼意思了。
 
 
另外一點,sizeof一般用於分配內存,這個特性特別在多維數組時,就能體現出其優點了
。如,給一個字符串數組分配內存,
 
/*
* 分配一個有20個字符串,
* 每個字符串長100的內存
*/
 
char* *p;
 
/*
* 錯誤的分配方法
*/
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) );
}
 
(注:上述語句被註釋掉的是原來的,是錯誤的,由dasherest朋友指正,謝謝)
 
爲了代碼的易讀,省去了一些判斷,請注意這兩種分配的方法,有本質上的差別。
 
 
 
31、不要忽略Warning
——————————
對於一些編譯時的警告信息,請不要忽視它們。雖然,這些Warning不會妨礙目標代碼的生
成,但這並不意味着你的程序就是好的。必竟,並不是編譯成功的程序纔是正確的,編譯
成功只是萬里長征的第一步,後面還有大風大浪在等着你。從編譯程序開始,不但要改正
每個error,還要修正每個warning。這是一個有修養的程序員該做的事。
 
一般來說,一面的一些警告信息是常見的:
 
 
    1)聲明瞭未使用的變量。(雖然編譯器不會編譯這種變量,但還是把它從源程序中注
釋或是刪除吧)
    2)使用了隱晦聲明的函數。(也許這個函數在別的C文件中,編譯時會出現這種警告
,你應該這使用之前使用extern關鍵字聲明這個函數)
    3)沒有轉換一個指針。(例如malloc返回的指針是void的,你沒有把之轉成你實際類
型而報警,還是手動的在之前明顯的轉換一下吧)
    4)類型向下轉換。(例如:float f = 2.0; 這種語句是會報警告的,編譯會告訴你
正試圖把一個double轉成float,你正在閹割一個變量,你真的要這樣做嗎?還是在2.0後
面加個f吧,不然,2.0就是一個double,而不是float了)
 
不管怎麼說,編譯器的Warning不要小視,最好不要忽略,一個程序都做得出來,何況幾個
小小的Warning呢?
 
 
 
32、書寫Debug版和Release版的程序
————————————————
程序在開發過程中必然有許多程序員加的調試信息。我見過許多項目組,當程序開發結束
時,發動羣衆刪除程序中的調試信息,何必呢?爲什麼不像VC++那樣建立兩個版本的目標
代碼?一個是debug版本的,一個是Release版的。那些調試信息是那麼的寶貴,在日後的
維護過程中也是很寶貴的東西,怎麼能說刪除就刪除呢?
 
 
利用預編譯技術吧,如下所示聲明調試函數:
#ifdef DEBUG
        void TRACE(char* fmt, ...)
        {
            ......
        }
    #else
        #define TRACE(char* fmt, ...)
    #endif
 
於是,讓所有的程序都用TRACE輸出調試信息,只需要在在編譯時加上一個參數“-DDEBUG
”,如:
 
    cc -DDEBUG -o target target.c
 
於是,預編譯器發現DEBUG變量被定義了,就會使用TRACE函數。而如果要發佈給用戶了,
那麼只需要把取消“-DDEBUG”的參數,於是所有用到TRACE宏,這個宏什麼都沒有,所以
源程序中的所有TRACE語言全部被替換成了空。一舉兩得,一箭雙鵰,何樂而不爲呢?
 
順便提一下,兩個很有用的系統宏,一個是“__FILE__”,一個是“__LINE__”,分別表
示,所在的源文件和行號,當你調試信息或是輸出錯誤時,可以使用這兩個宏,讓你一眼
就能看出你的錯誤,出現在哪個文件的第幾行中。這對於用C/C++做的大工程非常的管用。
 
綜上所述32條,都是爲了三大目的——
 
 
    2、程序代碼的可維護性,
    3、程序代碼的穩定可靠性。
 
 
的細小的問題,編程高手不僅技術要強,基礎要好,而且最重要的是要有“修養”!
 
 
 
軟件的維護有大量的工作量花在代碼的維護上,軟件的Upgrade,也有大量的工作花在代碼
的組織上,所以好的代碼,清淅的,易讀的代碼,將給大大減少軟件的維護和升級成本。

發佈了11 篇原創文章 · 獲贊 6 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章