程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 我為什麼不用do{}while()

我為什麼不用do{}while()

編輯:關於C語言

這是個很意外的話題,我前兩天發布了一篇博文,《C語言學習中的變參處理》http://tonyxiaohome.blog.51cto.com/925273/314371),沒想到引起了爭論。 這裡面,爭論最大的就是裡面的變參處理宏,為什麼沒有用do{}while(0)封裝,而是直接用大括號{}封裝。 應該說,大量這種討論,有點出乎我的意料。我寫這篇博文,本意是講如何處理變參,用函數型宏來處理,算是一個處理方法,是為處理變參這個中心思想服務的,我心裡想的,更多的是大家從這篇博文中,能學到處理變參傳參的技巧,以後直接應用到工作和學習中,但是,我還真沒想到,很多高手、准高手,沒有關注變參處理這個中心思想,而把目光放在了宏的書寫本身上。 這讓我有點買椟還珠的感覺。 我說句實在話,大家以後看博文,最好還是看看博主真正想說什麼,別老是帶著自己的思路去看別人的文章,不然,挑了一大堆錯誤,結果,博主的想說的主要意思沒理解到,除了可以可以顯得自己比較牛之外,確實不容易學到東西。 我的書《 0bug-C/C++商用工程之道》其實就遇到過這種情況,大多數讀者是很愛學習的,但是,確實有少部分人,看書的目的就是找錯誤,很多時候,甚至根本不管書中原文到底在講什麼,只管按照自己熟悉的方向,找錯誤。 這裡面什麼心態都有哈,不排除某些個槍手帶著目的刻意而為,但我想至少有相當一部分人,可能是這麼想的:“啊哈,這個書這裡有個bug,這個作者在這點不如我,我得寫點什麼或者說點,顯得我比作者高明,作者的水平不過如此!”。 於是乎,拍磚的,噴人的,PK的,就都來了。很多時候話還很難聽,讓我很不好回答,最後只有刪帖了事。 這裡呢,我提個建議,聽不聽在大家。我建議大家以後遇到書籍、博文、演講什麼的,先不忙罵,也不要預設立場,先聽聽,看人家講的有沒有自己不足之處,有的話,把人家的東東學過來,而自己的東東,自己又沒有講,人家學不去,你不是賺了嘛。呵呵。 我們程序員,看文檔時經常會碰到一個單詞,Context,就是上下文,這話呢,翻譯到中國話就是前因後果,很多時候,文章中一句話,必須結合著上下文來分析,是有前提條件的,不能單獨就一句話來理解,這個道理,我想大家都知道。這裡,我也建議啊,大家看博文,耐心點,從頭到尾看完再說話,我發現很多人,沒耐心,看一點,或者文章中間看到一句話,就開罵,這至少不客觀對吧? 就好比年初我演講《明日世界--雲端計算下的程序員需求》,就有人,看了不到十分鐘就開罵,說講得很爛。我暈,我講了倆小時呢,120分鐘,我問他,他看書是不是也只看十分之一就開罵?他就不說話了。 我想我說這番話,倒不全是因為我是博主、作者、演講者,很多時候,我們從客觀的角度出發,要想了解別人的一段話,起碼讀完再說嘛,這個要求不過分吧? 好吧,言歸正傳,故事的起因是這樣的,我在《C語言學習中的變參處理》中,有這麼一段: Code:

  1. #define TONY_FORMAT(nPrintLength,szBuf,nBufferSize,szFormat) \       
  2. { \       
  3.     va_list pArgList; \       
  4.     va_start (pArgList,szFormat); \       
  5.     nPrintLength+=Linux_Win_vsnprintf(szBuf+nPrintLength, \       
  6.         nBufferSize-nPrintLength,szFormat,pArgList); \       
  7.     va_end(pArgList); \       
  8.     if(nPrintLength>(nBufferSize-1)) nPrintLength=nBufferSize-1; \       
  9.     *(szBuf+nPrintLength)='\0'; \       
  10. }      
由於我這裡沒有使用do{}while(0)來封裝,因此,後文中我在if{}else{}配對中就必須加大括號: Code:
  1. #define TONY_LINE_MAX 1024      //最大一行輸出的字符數       
  2. //輸出到控制台       
  3. inline int TonyPrintf(bool bWithTimestamp,      //是否帶時間戳標志       
  4.                       char* szFormat, ...)      //格式化字符串       
  5. {       
  6.     if(!szFormat) return 0;       
  7.     char szBuf[TONY_LINE_MAX];       
  8.     int nLength=0;       
  9.     if(!bWithTimestamp)                
  10.     {   //注意,由於內部是函數型宏,if...else這個大括號必不可少       
  11.         TONY_FORMAT(nLength,szBuf,TONY_LINE_MAX,szFormat);       
  12.     }   //注意,由於內部是函數型宏,if...else這個大括號必不可少       
  13.     else      
  14.     {   //注意,由於內部是函數型宏,if...else這個大括號必不可少       
  15.         TONY_FORMAT_WITH_TIMESTAMP(nLength,szBuf,TONY_LINE_MAX,szFormat);       
  16.     }   //注意,由於內部是函數型宏,if...else這個大括號必不可少       
  17.     return printf(szBuf);       
  18. }       
其實也可以不必加了,把宏調用後面的分號“;”去掉,就可以不加大括號,寫成下面這樣: Code:
  1. #define TONY_LINE_MAX 1024      //最大一行輸出的字符數       
  2. //輸出到控制台       
  3. inline int TonyPrintf(bool bWithTimestamp,      //是否帶時間戳標志       
  4.                       char* szFormat, ...)      //格式化字符串       
  5. {       
  6.     if(!szFormat) return 0;       
  7.     char szBuf[TONY_LINE_MAX];       
  8.     int nLength=0;       
  9.     if(!bWithTimestamp)                
  10.         TONY_FORMAT(nLength,szBuf,TONY_LINE_MAX,szFormat)  //注意,沒有分號   
  11.      else      
  12.          TONY_FORMAT_WITH_TIMESTAMP(nLength,szBuf,TONY_LINE_MAX,szFormat)  //注意,沒有分號   
  13.     return printf(szBuf);       
  14. }       
這本來是個細節問題,不過啊,引發爭議很多,因為大家從很多C語言庫中,可以看到這裡使用do{}while(0)來封裝,就沒有這個限制。 於是呼,就都來了,呵呵。 後來我沒辦法,只有給出詳細的解釋,我的程序中,是不用do{}while(0)的,原因如下: 唉,多說一點吧,我的0bug一書中有講,嚴禁一語多義,do{}while這個語句,寫循環的時候,完全可以用while()來代替,而且更精准。它在我看來,唯一的作用就是這個寫宏的時候用。這說明什麼,do{}while唯一的作用,就是做宏用,而不是做循環語句用,這豈止是一語多義,根本就是亂義,我認為對程序員的誤導極大。 我們都是通過學習循環語句學會的do{}while,但是,現在看起來,實際使用的時候,它更多被當成宏命令用,而不是循環語句,大家覺得亂不亂? 我很討厭這種掛羊頭賣狗肉的東東,所以,我的程序杜絕使用do{}while(),也嚴禁我的團隊程序員這麼使用,我不希望我們的代碼,字面上看起來是一個意思,實際上又是另外一個意思。我唯一付出的代價,就是如本文所述,在使用宏時,正好又碰到if{}else{},我需要顯式書寫大括號而已。 這是以前我和幾個做C的朋友討論了半天,確認的不容易寫錯和讀錯的辦法。這麼多年,差不多15年了,一直堅持這麼用,沒有出過問題。 C語言很靈活的,沒有什麼規定的標准,事實上,把do{}while()不當循環語句用,而是作為宏包容符,這本身就是典型的非標准寫法,大家想想是不是? 我寫這麼多,主要是想解釋一下,不用do{}while(),更多地是從規范化編程,減少bug,減少團隊bug這個出發點來的,並不是我不會用,更不是寫不好。是經過仔細評估過後,對C/C++語言做了很多規范性裁剪使用的結果,一個問題,有很多種解法,但是,我趨向於取一種最簡單的,最不容易出錯的,形成標准,這樣團隊開發才有效率。 事實上,《0bug-C/C++商用工程之道》這本書,通篇除了講並行,更多的就是講這種規范化開發,這雖然看起來,限制了程序員的隨意性和靈活度,但是,這保證了團隊開發的質量,能幫大家賺到錢,我就認為是好辦法。 08年我帶團隊,做的商用服務器集群,十幾萬行代碼,只有51個bug,屬於C/C++部分只有7個,這就是規范化開發的結果。這個故事在書上講了的。我知道大家都理解do{}while()可以用來做宏,我也知道,但是,我希望大家更多想想,怎麼寫不容易寫錯,也不容易讀錯的代碼,這樣的代碼,bug少,能賺錢,大家想不想寫呢? 我想,至少我寫程序不是為了炫耀,不是為了體現某些東東自己懂,別人不懂,顯得我好像高人一等是的。我想的更多的,是如何簡單、直接地輸出產品,沒有bug,大家賺到錢。我的這種思想,大家能同意不? do{}while()看似簡單,但背後體現程序設計規范化的思想,講起來很麻煩,大家看我回復這麼多,能理解吧? 喏,我想說的就是上面這段,如果還覺得不夠詳細呢,建議看看《0bug-C/C++商用工程之道》這本書,這也有個上下文問題,我定義的C/C++無錯化設計方法,背後是有一個思想和原則的,即在語言裁剪使用的時候,有個取捨的原則,這個書裡講得更詳細。看了,我想就能理解為什麼我在這裡捨掉do{}while()了。 也不一定要買書才能看啊,我的書,各大書店都有,有空的話,逛書店順便翻翻,看看第三章,就都明白了,我想這麼占便宜的事情,大家不會不去做吧,呵呵。   do{}while(0)很誤導人的,大家有興趣,看看這個例子: Code:
  1. int i=0;   
  2. do  
  3. {   
  4.     i++;   
  5. }while(0);   
  6. //i=?   
這麼說吧,while(0),顧名思義,循環0次,但是,i++被執行過沒有? 稍微對C語言不是特別熟悉的人,看到這段代碼,怎麼猜測i=? do{}while(0),語義含混,字面意思和實際意思截然相反,所以我不用它。 再看看這個例子: Code:
  1. void TestDoWhile(void)   
  2. {   
  3.     int i=0;   
  4.     i=0;   
  5.     do    
  6.     {   
  7.         i++;   
  8.         printf("i=%d\n",i);   
  9.     } while (0);   
  10.   
  11.     i=0;   
  12.     do    
  13.     {   
  14.         i++;            //程序陷入死循環   
  15.         printf("i=%d\n",i);   
  16.     } while (1);   
  17. }   
好家伙,do{}while(0)表示執行了1次,do{}while(1),表示執行無數次,大家覺得這個語義理解有沒有歧義,誤導人不?   好吧,先到這裡,我這裡呢,也算說點心裡話,很多時候,辛辛苦苦寫點東東出來,本來是出於一片好意,把自己一些研究心得share給大家,看能不能幫到人,就有人上來就開罵,看著確實很不舒服。大家說呢? =======================================================
在線底價購買我的書《0bug-C/C++商用工程之道》
直接點擊下面鏈接或拷貝到浏覽器地址欄)
http://s.click.taobao.com/t_3?&p=mm_13866629_0_0&n=23&l=http%3A%2F%2Fsearch8.taobao.com%2Fbrowse%2F0%2Fn-g%2Corvv64tborsvwmjvgawdkmbqgboq---g%2Cgaqge5lhebbs6qzlfmqmttgtyo42jm6m22xllqa-------------1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20---40--coefp-0-all-0.htm%3Fpid%3Dmm_13866629_0_0 肖舸

本文出自 “肖舸的blog” 博客,請務必保留此出處http://tonyxiaohome.blog.51cto.com/925273/315416

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved