久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

編程(下)

 雉水橋客 2011-10-29

編程---進(jìn)(下)

11,、出錯(cuò)信息的處理

你會(huì)處理出錯(cuò)信息嗎,?哦,它并不是簡(jiǎn)單的輸出,??聪旅娴氖纠?BR>
  if ( p == NULL ){
    printf ( "ERR: The pointer is NULLn" );
  }
  
告別學(xué)生時(shí)代的編程吧,。這種編程很不利于維護(hù)和管理,出錯(cuò)信息或是提示信息,,應(yīng)該統(tǒng)一處理,,而不是像上面這樣,寫成一個(gè)“硬編碼”,。第10條對(duì)這方面的處理做了一部分說明,。如果要管理錯(cuò)誤信息,那就要有以下的處理:

  
  #define   ERR_NO_ERROR  0 
  #define   ERR_OPEN_FILE  1 
  #define   ERR_SEND_MESG  2 
  #define   ERR_BAD_ARGS  3 
  #define   ERR_MEM_NONE  4 
  #define   ERR_SERV_DOWN  5 
  #define   ERR_UNKNOW_INFO 6 
  #define   ERR_SOCKET_ERR 7 
  #define   ERR_PERMISSION 8 
  #define   ERR_BAD_FORMAT 9 
  #define   ERR_TIME_OUT  10 
  
  
  char* errmsg[] = {
        "No error",        
        "Open file error",    
        "Failed in sending/receiving a message", 
        "Bad arguments", 
        "Memeroy is not enough",
        "Service is down; try later",
        "Unknow information",
        "A socket operation has failed",
        "ermission denied",
        "Bad configuration file format", 
       "Communication time out",
  };
               
  
  long errno = 0;
  
  
  void perror( char* info)
  {
    if ( info ){
      printf("%s: %sn", info, errmsg[errno] );
      return;
    }
    
    printf("Error: %sn", 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)手吧,。

同樣,對(duì)于常用函數(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í)都要對(duì)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) 名字的長(zhǎng)度應(yīng)該即要最短的長(zhǎng)度,,也要能最大限度的表達(dá)其含義。
3) 不要全部大寫,,也不要全部小寫,,應(yīng)該大小寫都有,如:GetLocalHostName 或是 UserAccount,。
4) 可以簡(jiǎn)寫,,但簡(jiǎn)寫得要讓人明白,如:ErrorCode -> ErrCode, ServerListener -> ServLisner,,UserAccount -> UsrAcct 等,。
5) 為了避免全局函數(shù)和變量名字沖突,可以加上一些前綴,,一般以模塊簡(jiǎn)稱做為前綴,。
6) 全局變量統(tǒng)一加一個(gè)前綴或是后綴,讓人一看到這個(gè)變量就知道是全局的,。
7) 用匈牙利命名法命名函數(shù)參數(shù),,局部變量,。但還是要堅(jiān)持“望文生意”的原則。
8) 與標(biāo)準(zhǔn)庫(kù)(如:STL)或開發(fā)庫(kù)(如: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
GetVersion(char* pStr)
{
  pStr = malloc(10);
  strcpy ( pStr, "2.0" );
}
main()
{
  char* ver = NULL;
  GetVersion ( ver );
  ...
  ...
  free ( ver );
}

我保證,類似這樣的問題是一個(gè)新手最容易犯的錯(cuò)誤,。程序中妄圖通過函數(shù)GetVersion給指針ver分配空間,,但這種方法根本沒有什么作用,原因就是--這是傳值,,不是傳指針,。你或許會(huì)和我爭(zhēng)論,我分明傳的時(shí)指針???再仔細(xì)看看,其實(shí),,你傳的是指針其實(shí)是在傳值,。

15、修改別人程序的修養(yǎng)

當(dāng)你維護(hù)別人的程序時(shí),,請(qǐng)不要非常主觀臆斷的把已有的程序刪除或是修改,。我經(jīng)常看到有的程序員直接在別人的程序上修改表達(dá)式或是語句,。修改別人的程序時(shí),,請(qǐng)不要?jiǎng)h除別人的程序,如果你覺得別人的程序有所不妥,,請(qǐng)注釋掉,,然后添加自己的處理程序,必竟,你不可能100%的知道別人的意圖,,所以為了可以恢復(fù),,請(qǐng)不依賴于CVS或是SourceSafe這種版本控制軟件,還是要在源碼上給別人看到你修改程序的意圖和步驟,。這是程序維護(hù)時(shí),,一個(gè)有修養(yǎng)的程序員所應(yīng)該做的。

如下所示,,這就是一種比較好的修改方法:

  
  
  
   char* p = ( char* )calloc( 10, sizeof char );
  
  ...

當(dāng)然,,這種方法是在軟件維護(hù)時(shí)使用的,這樣的方法,,可以讓再維護(hù)的人很容易知道以前的代碼更改的動(dòng)作和意圖,而且這也是對(duì)原作者的一種尊敬,。

以“注釋 - 添加”方式修改別人的程序,,要好于直接刪除別人的程序。

16,、把相同或近乎相同的代碼形成函數(shù)和宏

有人說,,最好的程序員,就是最喜歡“偷懶”的程序,,其中不無道理,。

如果你有一些程序的代碼片段很相似,或直接就是一樣的,,請(qǐng)把他們放在一個(gè)函數(shù)中,。而如果這段代碼不多,而且會(huì)被經(jīng)常使用,,你還想避免函數(shù)調(diào)用的開銷,,那么就把他寫成宏吧。

千萬不要讓同一份代碼或是功能相似的代碼在多個(gè)地方存在,,不然如果功能一變,,你就要修改好幾處地方,這種會(huì)給維護(hù)帶來巨大的麻煩,,所以,,做到“一改百改”,還是要形成函數(shù)或是宏,。

17,、表達(dá)式中的括號(hào)

如果一個(gè)比較復(fù)雜的表達(dá)式中,你并不是很清楚各個(gè)操作符的憂先級(jí),,即使是你很清楚優(yōu)先級(jí),,也請(qǐng)加上括號(hào),不然,別人或是自己下一次讀程序時(shí),,一不小心就看走眼理解錯(cuò)了,,為了避免這種“誤解”,還有讓自己的程序更為清淅,,還是加上括號(hào)吧,。

比如,對(duì)一個(gè)結(jié)構(gòu)的成員取地址:

  GetUserAge( &( UserInfo->age ) );
雖然,,&UserInfo->age中,,->操作符的優(yōu)先級(jí)最高,但加上一個(gè)括號(hào),,會(huì)讓人一眼就看明白你的代碼是什么意思,。
再比如,一個(gè)很長(zhǎng)的條件判斷:
if ( ( ch[0] >= ′0′ || ch[0] <= ′9′ ) &&
   ( ch[1] >= ′a′ || ch[1] <= ′z′ ) &&
   ( ch[2] >= ′A′ || ch[2] <= ′Z′ )  )
  
括號(hào),,再加上空格和換行,,你的代碼是不是很容易讀懂了?  

18,、函數(shù)參數(shù)中的const

對(duì)于一些函數(shù)中的指針參數(shù),,如果在函數(shù)中只讀,請(qǐng)將其用const修飾,,這樣,,別人一讀到你的函數(shù)接口時(shí),就會(huì)知道你的意圖是這個(gè)參數(shù)是[in],,如果沒有const時(shí),,參數(shù)表示[in/out],注意函數(shù)接口中的const使用,,利于程序的維護(hù)和避免犯一些錯(cuò)誤,。

雖然,const修飾的指針,,如:const char* p,,在C中一點(diǎn)用也沒有,因?yàn)椴还苣愕穆暶魇遣皇莄onst,,指針的內(nèi)容照樣能改,,因?yàn)榫幾g器會(huì)強(qiáng)制轉(zhuǎn)換,但是加上這樣一個(gè)說明,,有利于程序的閱讀和編譯,。因?yàn)樵贑中,修改一個(gè)const指針?biāo)赶虻膬?nèi)存時(shí),,會(huì)報(bào)一個(gè)Warning,。這會(huì)引起程序員的注意,。

C++中對(duì)const定義的就很嚴(yán)格了,所以C++中要多多的使用const,,const的成員函數(shù),,const的變量,這樣會(huì)對(duì)讓你的代碼和你的程序更加完整和易讀,。(關(guān)于C++的const我就不多說了)

19,、函數(shù)的參數(shù)個(gè)數(shù)(多了請(qǐng)用結(jié)構(gòu))

函數(shù)的參數(shù)個(gè)數(shù)最好不要太多,一般來說6個(gè)左右就可以了,,眾多的函數(shù)參數(shù)會(huì)讓讀代碼的人一眼看上去就很頭昏,,而且也不利于維護(hù)。如果參數(shù)眾多,,還請(qǐng)使用結(jié)構(gòu)來傳遞參數(shù),。這樣做有利于數(shù)據(jù)的封裝和程序的簡(jiǎn)潔性。

也利于使用函數(shù)的人,,因?yàn)槿绻愕暮瘮?shù)個(gè)數(shù)很多,,比如12個(gè),調(diào)用者很容易搞錯(cuò)參數(shù)的順序和個(gè)數(shù),,而使用結(jié)構(gòu)struct來傳遞參數(shù),就可以不管參數(shù)的順序,。

而且,,函數(shù)很容易被修改,如果需要給函數(shù)增加參數(shù),,不需要更改函數(shù)接口,,只需更改結(jié)構(gòu)體和函數(shù)內(nèi)部處理,而對(duì)于調(diào)用函數(shù)的程序來說,,這個(gè)動(dòng)作是透明的,。

20、函數(shù)的返回類型,,不要省略

我看到很多程序?qū)懞瘮?shù)時(shí),,在函數(shù)的返回類型方面不太注意。如果一個(gè)函數(shù)沒有返回值,,也請(qǐng)?jiān)诤瘮?shù)前面加上void的修飾,。而有的程序員偷懶,在返回int的函數(shù)則什么不修飾(因?yàn)槿绻恍揎?,則默認(rèn)返回int),,這種習(xí)慣很不好,還是為了原代碼的易讀性,,加上int吧,。
所以函數(shù)的返回值類型,,請(qǐng)不要省略。

另外,,對(duì)于void的函數(shù),,我們往往會(huì)忘了return,由于某些C/C++的編譯器比較敏感,,會(huì)報(bào)一些警告,,所以即使是void的函數(shù),我們?cè)趦?nèi)部最好也要加上return的語句,,這有助于代碼的編譯,。

21、goto語句的使用

N年前,,軟件開發(fā)的一代宗師--迪杰斯特拉(Dijkstra)說過:“goto statment is harmful !!”,,并建議取消goto語句。因?yàn)間oto語句不利于程序代碼的維護(hù)性,。

這里我也強(qiáng)烈建議不要使用goto語句,,除非下面的這種情況:
  #define FREE(p) if(p) {
            free(p);
            p = NULL;
          }
  main()
  {
    char *fname=NULL, *lname=NULL, *mname=NULL;
    fname = ( char* ) calloc ( 20, sizeof(char) );
    if ( fname == NULL ){
      goto ErrHandle;
    }
    lname = ( char* ) calloc ( 20, sizeof(char) );
    if ( lname == NULL ){
      goto ErrHandle;
    }
    mname = ( char* ) calloc ( 20, sizeof(char) );
    if ( mname == NULL ){
      got-

o ErrHandle;
    }
    
    ......
  
    
   ErrHandle:
    FREE(fname);
    FREE(lname);
    FREE(mname);
    ReportError(ERR_NO_MEMOEY);
   }

也只有在這種情況下,goto語句會(huì)讓你的程序更易讀,,更容易維護(hù),。(在用嵌C來對(duì)數(shù)據(jù)庫(kù)設(shè)置游標(biāo)操作時(shí),或是對(duì)數(shù)據(jù)庫(kù)建立鏈接時(shí),,也會(huì)遇到這種結(jié)構(gòu))

22,、宏的使用

很多程序員不知道C中的“宏”到底是什么意思?特別是當(dāng)宏有參數(shù)的時(shí)候,,經(jīng)常把宏和函數(shù)混淆,。我想在這里我還是先講講“宏”,宏只是一種定義,,他定義了一個(gè)語句塊,,當(dāng)程序編譯時(shí),編譯器首先要執(zhí)行一個(gè)“替換”源程序的動(dòng)作,,把宏引用的地方替換成宏定義的語句塊,,就像文本文件替換一樣。這個(gè)動(dòng)作術(shù)語叫“宏的展開”

使用宏是比較“危險(xiǎn)”的,,因?yàn)槟悴恢篮暾归_后會(huì)是什么一個(gè)樣子,。例如下面這個(gè)宏:
  #define MAX(a, b)   a>b?a:b

當(dāng)我們這樣使用宏時(shí),沒有什么問題: MAX( num1, num2 ); 因?yàn)楹暾归_后變成 num1>num2?num1:num2,;,。但是,如果是這樣調(diào)用的,,MAX( 17+32, 25+21 ); 呢,,編譯時(shí)出現(xiàn)錯(cuò)誤,,原因是,宏展開后變成:17+32>25+21?17+32:25+21,,哇,,這是什么啊,?
所以,,宏在使用時(shí),參數(shù)一定要加上括號(hào),,上述的那個(gè)例子改成如下所示就能解決問題了,。

  #define MAX( (a), (b) )   (a)>(b)?(a)b)
  
即使是這樣,也不這個(gè)宏也還是有Bug,,因?yàn)槿绻疫@樣調(diào)用 MAX(i++, j++); ,,經(jīng)過這個(gè)宏以后,i和j都被累加了兩次,,這絕不是我們想要的,。
  
所以,在宏的使用上還是要謹(jǐn)慎考慮,,因?yàn)楹暾归_是的結(jié)果是很難讓人預(yù)料的,。而且雖然,宏的執(zhí)行很快(因?yàn)闆]有函數(shù)調(diào)用的開銷),,但宏會(huì)讓源代碼澎漲,,使目標(biāo)文件尺寸變大,(如:一個(gè)50行的宏,,程序中有1000個(gè)地方用到,宏展開后會(huì)很不得了),,相反不能讓程序執(zhí)行得更快(因?yàn)閳?zhí)行文件變大,,運(yùn)行時(shí)系統(tǒng)換頁(yè)頻繁)。

因此,,在決定是用函數(shù),,還是用宏時(shí)得要小心。

23,、static的使用

static關(guān)鍵字,,表示了“靜態(tài)”,一般來說,,他會(huì)被經(jīng)常用于變量和函數(shù),。一個(gè)static的變量,其實(shí)就是全局變量,,只不過他是有作用域的全局變量,。比如一個(gè)函數(shù)中的static變量:

char*
getConsumerName()
{
  static int cnt = 0;
  
  ....
  cnt++;
  ....
}

cnt變量的值會(huì)跟隨著函數(shù)的調(diào)用次而遞增,,函數(shù)退出后,cnt的值還存在,,只是cnt只能在函數(shù)中才能被訪問,。而cnt的內(nèi)存也只會(huì)在函數(shù)第一次被調(diào)用時(shí)才會(huì)被分配和初始化,以后每次進(jìn)入函數(shù),,都不為static分配了,,而直接使用上一次的值。

對(duì)于一些被經(jīng)常調(diào)用的函數(shù)內(nèi)的常量,,最好也聲明成static(參見第12條)

但static的最多的用處卻不在這里,,其最大的作用的控制訪問,在C中如果一個(gè)函數(shù)或是一個(gè)全局變量被聲明為static,,那么,,這個(gè)函數(shù)和這個(gè)全局變量,將只能在這個(gè)C文件中被訪問,,如果別的C文件中調(diào)用這個(gè)C文件中的函數(shù),,或是使用其中的全局(用extern關(guān)鍵字),將會(huì)發(fā)生鏈接時(shí)錯(cuò)誤,。這個(gè)特性可以用于數(shù)據(jù)和程序保密,。

24、函數(shù)中的代碼尺寸

一個(gè)函數(shù)完成一個(gè)具體的功能,,一般來說,,一個(gè)函數(shù)中的代碼最好不要超過600行左右,越少越好,,最好的函數(shù)一般在100行以內(nèi),,300行左右的孫函數(shù)就差不多了。有證據(jù)表明,,一個(gè)函數(shù)中的代碼如果超過500行,,就會(huì)有和別的函數(shù)相同或是相近的代碼,也就是說,,就可以再寫另一個(gè)函數(shù),。

另外,函數(shù)一般是完成一個(gè)特定的功能,,千萬忌諱在一個(gè)函數(shù)中做許多件不同的事,。函數(shù)的功能越單一越好,一方面有利于函數(shù)的易讀性,,另一方面更有利于代碼的維護(hù)和重用,,功能越單一表示這個(gè)函數(shù)就越可能給更多的程序提供服務(wù),也就是說共性就越多,。

雖然函數(shù)的調(diào)用會(huì)有一定的開銷,,但比起軟件后期維護(hù)來說,,增加一些運(yùn)行時(shí)的開銷而換來更好的可維護(hù)性和代碼重用性,是很值得的一件事,。

25,、typedef的使用

typedef是一個(gè)給類型起別名的關(guān)鍵字。不要小看了它,,它對(duì)于你代碼的維護(hù)會(huì)有很好的作用,。比如C中沒有bool,于是在一個(gè)軟件中,,一些程序員使用int,,一些程序員使用short,會(huì)比較混亂,,最好就是用一個(gè)typedef來定義,,如:

  typedef char bool;
  
一般來說,一個(gè)C的工程中一定要做一些這方面的工作,,因?yàn)槟銜?huì)涉及到跨平臺(tái),,不同的平臺(tái)會(huì)有不同的字長(zhǎng),所以利用預(yù)編譯和typedef可以讓你最有效的維護(hù)你的代碼,,如下所示:

  #ifdef SOLARIS2_5
   typedef boolean_t   BOOL_T;
  #else
   typedef int      BOOL_T;
  #endif
  
  typedef short      INT16_T;
  typedef unsigned short UINT16_T;
  typedef int       INT32_T;
  typedef unsigned int  UINT32_T;
  
  #ifdef WIN32
   typedef _int64    INT64_T;
  #else
   typedef long long   INT64_T;
  #endif
  
  typedef float      FLOAT32_T;
  typedef char*      STRING_T;
  typedef unsigned char  BYTE_T;
  typedef time_t     TIME_T;
  typedef INT32_T     PID_T;
  
使用typedef的其它規(guī)范是,,在結(jié)構(gòu)和函數(shù)指針時(shí),也最好用typedef,,這也有利于程序的易讀和可維護(hù)性,。如:

  typedef struct _hostinfo {
    HOSTID_T  host;
    INT32_T  hostId;
    STRING_T  hostType;
    STRING_T  hostModel;
    FLOAT32_T cpuFactor;
    INT32_T  numCPUs;
    INT32_T  nDisks;
    INT32_T  memory;
    INT32_T  swap;
  } HostInfo;
  typedef INT32_T (*RsrcReqHandler)(
   void *info,
   JobArray *jobs,
   AllocInfo *allocInfo,
   AllocList *allocList);

C++中這樣也是很讓人易讀的:

  typedef CArray<HostInfo, HostInfo&> HostInfoArray;

于是,當(dāng)我們用其定義變量時(shí),,會(huì)顯得十分易讀,。如:

  HostInfo* phinfo;
  RsrcReqHandler* pRsrcHand;
這種方式的易讀性,在函數(shù)的參數(shù)中十分明顯,。

關(guān)鍵是在程序種使用typedef后,,幾乎所有的程序中的類型聲明都顯得那么簡(jiǎn)潔和清淅,而且易于維護(hù),,這才是typedef的關(guān)鍵。

26,、為常量聲明宏

最好不要在程序中出現(xiàn)數(shù)字式的“硬編碼”,,如:

  int user[120];
  
為這個(gè)120聲明一個(gè)宏吧。為所有出現(xiàn)在程序中的這樣的常量都聲明一個(gè)宏吧,。比如TimeOut的時(shí)間,,最大的用戶數(shù)量,還有其它,,只要是常量就應(yīng)該聲明成宏,。如果,,突然在程序中出現(xiàn)下面一段代碼,

  for ( i=0; i<120; i++){
    ....
  }

120是什么,?為什么會(huì)是120,?這種“硬編碼”不僅讓程序很讀,而且也讓程序很不好維護(hù),,如果要改變這個(gè)數(shù)字,,得同時(shí)對(duì)所有程序中這個(gè)120都要做修改,這對(duì)修改程序的人來說是一個(gè)很大的痛苦,。所以還是把常量聲明成宏,,這樣,一改百改,,而且也很利于程序閱讀,。

  #define MAX_USR_CNT 120
  
  for ( i=0; i<MAX_USER_CNT; i++){
    ....
  }

這樣就很容易了解這段程序的意圖了。

有的程序員喜歡為這種變量聲明全局變量,,其實(shí),,全局變量應(yīng)該盡量的少用,全局變量不利于封裝,,也不利于維護(hù),,而且對(duì)程序執(zhí)行空間有一定的開銷,一不小心就造成系統(tǒng)換頁(yè),,造成程序執(zhí)行速度效率等問題,。所以聲明成宏,即可以免去全局變量的開銷,,也會(huì)有速度上的優(yōu)勢(shì),。

27、不要為宏定義加分號(hào)

有許多程序員不知道在宏定義時(shí)是否要加分號(hào),,有時(shí),,他們以為宏是一條語句,應(yīng)該要加分號(hào),,這就錯(cuò)了,。當(dāng)你知道了宏的原理,你會(huì)贊同我為會(huì)么不要為宏定義加分號(hào)的,??匆粋€(gè)例子:

  #define MAXNUM 1024;
這是一個(gè)有分號(hào)的宏,如果我們這樣使用:
  half = MAXNUM/2;
  
  if ( num < MAXNUM )
等等,,都會(huì)造成程序的編譯錯(cuò)誤,,因?yàn)椋?dāng)宏展開后,他會(huì)是這個(gè)樣子的:
  half = 1024;/2;
  
  if ( num < 1024; )
  
是的,,分號(hào)也被展進(jìn)去了,,所以造成了程序的錯(cuò)誤。請(qǐng)相信我,,有時(shí)候,,一個(gè)分號(hào)會(huì)讓你的程序出現(xiàn)成百個(gè)錯(cuò)誤。所以還是不要為宏加最后一個(gè)分號(hào),,哪怕是這樣:
  #define LINE  "================================="
  
  #define PRINT_LINE printf(LINE)
  #define PRINT_NLINE(n) while ( n-- >0 ) { PRINT_LINE; }
  
都不要在最后加上分號(hào),,當(dāng)我們?cè)诔绦蛑惺褂脮r(shí),為之加上分號(hào),,
  main()
  {
    char *p = LINE;
    PRINT_LINE;
  }
這一點(diǎn)非常符合習(xí)慣,,而且,如果忘加了分號(hào),,編譯器給出的錯(cuò)誤提示,,也會(huì)讓我們很容易看懂的。

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 hundredn");
     ......
  }
  
  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;
  
  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 
對(duì)于filename: sizeof(char) * 20 
對(duì)于usr:    sizeof(struct UserInfo) * 100 

這樣的代碼是不是很易讀,?一眼看上去就知道什么意思了。

另外一點(diǎn),,sizeof一般用于分配內(nèi)存,,這個(gè)特性特別在多維數(shù)組時(shí),就能體現(xiàn)出其優(yōu)點(diǎn)了,。如,,給一個(gè)字符串?dāng)?shù)組分配內(nèi)存,

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) );
}

(注:上述語句被注釋掉的是原來的,,是錯(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ù),。(也許此函數(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條,都是為了三大目的--

  1,、程序代碼的易讀性,。
  2、程序代碼的可維護(hù)性,,
  3,、程序代碼的穩(wěn)定可靠性。
  
有修養(yǎng)的程序員,,就應(yīng)該要學(xué)會(huì)寫出這樣的代碼,!這是任何一個(gè)想做編程高手所必需面對(duì)的細(xì)小的問題,,編程高手不僅技術(shù)要強(qiáng),基礎(chǔ)要好,,而且最重要的是要有“修養(yǎng)”,!

好的軟件產(chǎn)品絕不僅僅是技術(shù),而更多的是整個(gè)軟件的易維護(hù)和可靠性,。
  
軟件的維護(hù)有大量的工作量花在代碼的維護(hù)上,,軟件的Upgrade,也有大量的工作花在代碼的組織上,,所以好的代碼,,清淅的,易讀的代碼,,將給大大減少軟件的維護(hù)和升級(jí)成本。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多