編程精粹理解.ppt_第1頁
編程精粹理解.ppt_第2頁
編程精粹理解.ppt_第3頁
編程精粹理解.ppt_第4頁
編程精粹理解.ppt_第5頁
已閱讀5頁,還剩20頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、編寫無錯的程序,作為一個程序員,你在寫每一行代碼時應(yīng)該始終保持如履薄冰的危機(jī)感。,由來,編程精粹,Steve Maguire,電子工業(yè)出版社 作者是Microsoft公司資深項(xiàng)目主管 以下的內(nèi)容是個人對此書的理解,與大家共同探討,概述,基本要求 總則 函數(shù)的設(shè)計(jì) 函數(shù)的實(shí)現(xiàn) 編譯、調(diào)試、修改、合版本 進(jìn)一步的建議 設(shè)計(jì) 實(shí)現(xiàn) 超越編碼 攻擊錯誤,總則,確立并堅(jiān)持編碼的優(yōu)先順序我們推薦的編碼優(yōu)先順序: 正確性 可維護(hù)性/可讀性 可測試性 全局效率 一致性 大小 局部效率 個人表達(dá)方式/個人方便性 建立程序的DEBUG版本,同時維護(hù)DEBUG版本和發(fā)行版本。在DEBUG版本中加入能暴露程序錯誤的代

2、碼。 堅(jiān)持徹底測試代碼(單元測試),即使延誤進(jìn)度。不要依靠測試組測試你的代碼。 不要責(zé)怪測試員發(fā)現(xiàn)你的錯誤(驚訝,怎么會有這樣的問題?然后感謝測試員在問題到用戶手中之前發(fā)現(xiàn)了它),函數(shù)的設(shè)計(jì),函數(shù)不僅僅要正確,而且在使用時要安全 (糖果機(jī)的界面) 函數(shù)的返回值不要同時作為錯誤代碼和正常的返回結(jié)果,讓使用者不容易忽視錯誤情況 仔細(xì)考慮函數(shù)的界面,是否容易被誤用(函數(shù)名稱、參數(shù)、返回值) 不要定義多用途且面面俱到的函數(shù) 不要設(shè)計(jì)太靈活的(無確切含義、空空洞洞)函數(shù)參數(shù) 讓你的函數(shù)在調(diào)用點(diǎn)顯得易讀 不要使用布爾參數(shù)輸入 編寫函數(shù),使其在有效輸入情況下不會失敗,減少調(diào)用者的錯誤檢查 使用注釋突出使用時

3、可能的異常情況,返回值,函數(shù)的返回值不要同時作為錯誤代碼和正常的返回結(jié)果,讓使用者不容易忽視錯誤情況 風(fēng)險的代碼 char c ; c = getchar() ; if (c = EOF) ? 問題 getch()返回int型 在stdio.h種,#define EOF (-1) 如果變量 c 是無符號字符,if語句永遠(yuǎn)不會成立 換一種做法 flag fGetChar(char * pch) ; char ch ; if (fGetCh( if (pbBuf != NULL) 問題 如果僅有pbBuf引用其指向的內(nèi)存,在分配失敗時出現(xiàn)內(nèi)存泄露 換一種做法 flag fResizeMemory(

4、void *ppv, size_t sizeNew) byte * ppb = (byte *)ppv ; byte * pbResize ; pbResize = (byte *)realloc(*ppb, sizeNew) ; if (pbResize != NULL) * ppb = pbResize ; return (pbResize != NULL) ; ,不要定義面面俱到的函數(shù),風(fēng)險的代碼 void * realloc(void *pv, sizet size) ; 如果內(nèi)存塊的新長度小于老長度 如果內(nèi)存塊的新長度大于老長度 如果內(nèi)存不夠 如果pv是NULL = malloc 如

5、果pv不是NULL,但新長度為0 = free 如果pv是NULL,新長度為0 = ? 問題 對不同pv的操作是否有用? 如何處理這些情況? 換一種做法 ASSERT的使用,pv = NULL | size = 0 fGrowMemory(void *ppv, size_t sizeLarger) ; fShrinkMemory(void *pv, size_t sizeSmaller) ;,明確定義函數(shù)參數(shù),避免摸棱兩可,風(fēng)險 char *CopySubStr(char * strTo, char *strFrom, size_t size) ; char * strStart = strT

6、o ; while (size - 0) * strTo + = * strFrom + ; *strTo = 0 ; return strStart) ; 問題 如果size大于strFrom的長度,? 換一種做法 明確規(guī)定,strFrom必須包含size個字符 ASSERT(strTo!=NULL void UnsignedToHexStr(unsigned u, char * str) ;,返回失敗的函數(shù),編寫函數(shù),使其在有效輸入情況下不會失敗 減少調(diào)用者的錯誤檢查 風(fēng)險的代碼 char tolower(char ch) if (ch =A 換一種做法 如果輸入不是字母,則返回輸入的字符

7、 不接收非字母的輸入(ASSERT),函數(shù)的注釋,使用注釋突出使用時可能的異常情況 風(fēng)險的代碼 pv = realloc( pv, sizeNew) ; 問題 內(nèi)存泄露 替你的客戶著想 /* realloc(pv, size) 典型用法: void * pvNew ; pvNew = realloc(pv, sizeNew) ; if ( NULL != pvNew ) pv = pvNew ; / success else / failue / pvNew為NULL,不要丟掉pv的內(nèi)存 */,實(shí)現(xiàn),保證程序良好的可讀性,保證代碼的中注釋行與空行所占比例大于30% 使用斷言。在以下情況下應(yīng)該使

8、用斷言: 利用斷言確認(rèn)函數(shù)的參數(shù) 用斷言保證沒有定義的特性不被使用(或者去除無定義的特性). 將你對程序開發(fā)運(yùn)行環(huán)境(OS, Compiler, Hardware)的假設(shè)用斷言給出 用斷言檢查不可能發(fā)生的情況 編寫防錯性處理程序,但防止錯誤之后用斷言宣布發(fā)生錯誤 對復(fù)雜的斷言加上注釋 盡量編寫和測試小塊代碼,即使測試影響進(jìn)度,函數(shù)規(guī)模限制在200行以內(nèi) 使用嚴(yán)格定義的、可移植的數(shù)據(jù)類型 避免使用嵌套的?:運(yùn)算符 一個任務(wù)應(yīng)該一次完成(如果多段代碼重復(fù)做同一件事,意味者存在問題) 避免無關(guān)緊要的if語句(草率設(shè)計(jì)、粗心實(shí)現(xiàn)的結(jié)果) 對特殊情況,只在程序的一個地方處理 不同類型的操作符混合使用時,

9、使用括號隔離之 盡量避免使用返回錯誤的函數(shù),斷言,斷言的實(shí)現(xiàn) #ifdef NDEBUG #define assert(p) (void)0) #else # define assert(p) (p) ? (void)0 : (void) _assertfail( Assertion failed: %s, file %s, line %d _ENDL, #p, _FILE_, _LINE_ ) ) #endif 斷言與錯誤處理 斷言不等于錯誤處理 char *pcM = (char *) malloc(sizeWant) ; ASSERT(NULL != pcM) ; 。 。 斷言不等同與狀

10、態(tài)提示 VC+中的TRACE,斷言的使用(一),利用斷言確認(rèn)函數(shù)的參數(shù) void memcpy(void *pvTo, void *pvFrom, size_t size) assert( NULL != pvTo 。 。,斷言的使用(二),用斷言檢查不可能發(fā)生的情況 switch state) 。 default: ASSERT(FALSE) ; 編寫防錯性處理程序,但防止錯誤之后用斷言宣布發(fā)生錯誤 / get Name from self-gen temp. file. Extern file * pfSaveBuffFile ; BOOL getName(char * pcName) i

11、f (8 != fread(pcName, 1, 7, fpSaveBuffFile) / this must not occur ASSERT(FALSE) ; / do some thing 。 。 對復(fù)雜的斷言加上注釋,實(shí)現(xiàn)(陷阱的回避),盡量編寫和測試小塊代碼,即使測試影響進(jìn)度,函數(shù)規(guī)模限制在200行以內(nèi) 使用嚴(yán)格定義的、可移植的數(shù)據(jù)類型 High C環(huán)境下B型機(jī)的數(shù)據(jù)類型 typedef unsigned short _UI; typedef unsigned char _UC; typedef unsigned short _US; typedef unsigned int _UL

12、; 不同類型的操作符混合使用時,使用括號隔離之 混合操作類型 word = high 8 + low ; / 運(yùn)算符優(yōu)先級錯誤 while (ch = getchar() != EOF) . 換一種做法 word = high 8 | low ; word = high * 256 + low ; while (ch = getchar() != EOF) . 盡量避免使用返回錯誤的函數(shù) 讓函數(shù)始終正確工作 將同樣的錯誤處理部分獨(dú)立開來,實(shí)現(xiàn)(消除冗余,改進(jìn)算法),提示 一個任務(wù)應(yīng)該一次完成(如果多段代碼重復(fù)做同一件事,意味者存在問題) 避免無關(guān)緊要的if語句(草率設(shè)計(jì)、粗心實(shí)現(xiàn)的結(jié)果) 避免

13、使用嵌套的?:運(yùn)算符 對特殊情況,只在程序的一個地方處理 理由 避免維護(hù)中無意識地遺漏而導(dǎo)致錯誤。 簡單地解決讓程序員不再話時間尋找更號的解決方法。,實(shí)現(xiàn)(消除冗余,改進(jìn)算法),代碼(一) void * memchr(void *pv, unsigned char ch, size_t, size) unsigned char * pch = (unsignecd char *) pv ; unsigned char * pchEnd = pch + size ; while (pch pchEnd ,實(shí)現(xiàn)(消除冗余,改進(jìn)算法),代碼(二) if (NULL = pHead-next) pHe

14、ad-next = pNew ; else TNode * pGo = pHead-next ; while (pGo-next != NULL) pGo = pGo-next ; pGo-next = pNew ; 換一種做法 pGo-next = pHead ; while (pGo-next != NULL) pGo = pGo-next ; pGo-next = pNew ;,進(jìn)一步考慮(設(shè)計(jì)),設(shè)計(jì)一個特征前,先仔細(xì)考慮是否是用戶需要 不設(shè)自由特征 不允許沒有必要的靈活性 對關(guān)鍵的算法使用二個算法來確認(rèn)前者 不要等待錯誤發(fā)生,在代碼啟動前使用初始檢查程序以保證程序運(yùn)行環(huán)境的一致性,進(jìn)

15、一步考慮(實(shí)現(xiàn)),時刻注意表達(dá)式是否會上溢、下溢 明確設(shè)計(jì),并精確(不是近似)實(shí)現(xiàn)設(shè)計(jì) 避免使用有風(fēng)險的語言慣用語 只引用屬于自己的存貯空間 注意是否引用已經(jīng)釋放的空間 指向輸出的指針不是指向工作緩沖區(qū)的指針 避免向靜態(tài)(全局)變量存貯區(qū)傳遞數(shù)據(jù) 不要編寫依賴于其他函數(shù)內(nèi)部實(shí)現(xiàn)的函數(shù) 不要使用希奇古怪的C慣用語 不要追求緊湊的代碼(不代表高效的機(jī)器碼) 考慮你的代碼將給新手讀,超越編碼,消除代碼運(yùn)行的隨機(jī)性,使錯誤可再現(xiàn)。去除未定義的(隨機(jī)的)特性、無用的數(shù)據(jù)內(nèi)容等。 在DEBUG版中將無用的信息抹掉(換以固定的數(shù)字),以免被錯誤使用 如果某件事很少發(fā)生,設(shè)法使其經(jīng)常發(fā)生。確定子系統(tǒng)會發(fā)生哪些

16、事情,并使它們經(jīng)常發(fā)生;如果發(fā)現(xiàn)子系統(tǒng)中有很少發(fā)生的行為,千方百計(jì)使其重現(xiàn)。 保存內(nèi)部調(diào)試信息,進(jìn)行更強(qiáng)的錯誤檢查 主動出擊,建立子系統(tǒng)檢查,在適當(dāng)時候確認(rèn)子系統(tǒng)的狀態(tài) 仔細(xì)設(shè)計(jì)程序的測試代碼,任何選擇都應(yīng)該經(jīng)過考慮 設(shè)計(jì)透明的一致性檢查,在正常的程序運(yùn)行過程中自動檢查一致性 保證DEBUG版本的運(yùn)行,即使其大小和速度不盡人意,超越編碼(讓錯誤固定出現(xiàn)),消除代碼運(yùn)行的隨機(jī)性,使錯誤可再現(xiàn)。去除未定義的(隨機(jī)的)特性、無用的數(shù)據(jù)內(nèi)容等。 在DEBUG版中將無用的信息抹掉(換以固定的數(shù)字),以免被錯誤使用 如果某件事很少發(fā)生,設(shè)法使其經(jīng)常發(fā)生。確定子系統(tǒng)會發(fā)生哪些事情,并使它們經(jīng)常發(fā)生;如果發(fā)現(xiàn)

17、子系統(tǒng)中有很少發(fā)生的行為,千方百計(jì)使其重現(xiàn)。 代碼 void FreeMemory(void *pv) ASSERT(pv != NULL) ; #ifdef DEBUG memset(pv, bGarbage, sizeofBlock(pv) ; #endif free(pv) ; ,超越編碼(主動出擊),保存內(nèi)部調(diào)試信息,進(jìn)行更強(qiáng)的錯誤檢查 主動出擊,建立子系統(tǒng)檢查,在適當(dāng)時候確認(rèn)子系統(tǒng)的狀態(tài) 仔細(xì)設(shè)計(jì)程序的測試代碼,任何選擇都應(yīng)該經(jīng)過考慮 設(shè)計(jì)透明的一致性檢查,在正常的程序運(yùn)行過程中自動檢查一致性 代碼 flag fCreatBlockinfo(byte * pbNew, size_t sizeNew) ;

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論