程式設計修養(七) (轉)

amyz發表於2007-08-14
程式設計修養(七) (轉)[@more@]

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 ");
  ......
  }
 
  fprintf( fp, " sum is %id ", 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;
 
  while ( p ){
  ...
  ...
  p = p->next;
  }

當while的語句塊變大後,你的程式將很難讀,用for就好得多:

  for ( p=pHead;  p; p=p->next ){
  ..
  }

一眼就知道這個迴圈的開始條件,結束條件,和迴圈的推進。大約就能明白這個迴圈要做個什麼事?而且,程式維護進來很容易,不必像while一樣,在一個編輯器中上上下下的搗騰。

 

30、請sizeof型別而不是變數
—————————————

許多程式設計師在使用sizeof中,喜歡sizeof變數名,例如:

int re[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、書寫De版和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條,都是為了三大目的——

  1、程式程式碼的易讀性。
  2、程式程式碼的可維護性,
  3、程式程式碼的穩定可靠性。
 
有修養的程式設計師,就應該要學會寫出這樣的程式碼!這是任何一個想做高手所必需面對的細小的問題,程式設計高手不僅技術要強,基礎要好,而且最重要的是要有“修養”!

好的產品絕不僅僅是技術,而更多的是整個軟體的易維護和可靠性。 

軟體的維護有大量的工作量花在程式碼的維護上,軟體的Upgrade,也有大量的工作花在程式碼的組織上,所以好的程式碼,清淅的,易讀的程式碼,將給大大減少軟體的維護和升級成本。

/Develop/read_article.?id=18274"> 

(版權所有,轉載時請註明出處和作者資訊)


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-956448/,如需轉載,請註明出處,否則將追究法律責任。

相關文章