已閱讀5頁,還剩177頁未讀, 繼續(xù)免費(fèi)閱讀
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1 編程精粹 寫優(yōu)質(zhì)無錯 C 程序秘訣 文書名: 版 2 整理: 、某些背景、命名約定、引言、第 1、 2、 3、 8 章、后記、參考文獻(xiàn) 第 4、 5 章 第 6 章、附錄 A 第 7 章 附錄 B、 C 校對、格式編排: 錄 序 . 3 命名約定 . 5 某些背景 . 6 引言 . 7 第 1 章 假想的編譯程序 . 12 第 2 章 自己設(shè)計(jì)并使用斷言 . 20 第 3 章 為子系統(tǒng)設(shè)防 . 44 第 4 章 對程序進(jìn)行逐條跟蹤 . 67 第 5 章 糖果機(jī)界面 . 75 第 6 章 風(fēng)險事業(yè) . 91 第 7 章 編碼中的假象 . 115 第 8 章 剩下來的就是態(tài)度問題 . 133 附錄 A 編碼檢查表 . 148 附錄 B 內(nèi)存登錄例程 . 151 附錄 C 練習(xí)答案 . 159 后記 走向何方 . 182 序 某些背景 命名約定 3 引 言 第 1 章 假想的編譯程序 1 第 2 章 自己設(shè)計(jì)并使用斷言 8 第 3 章 為子系統(tǒng)設(shè)防 31 第 4 章 對程序進(jìn)行逐條跟蹤 53 第 5 章 糖果機(jī)界面 60 第 6 章 風(fēng)險事業(yè) 75 第 7 章 編碼中的假象 98 第 8 章 剩下的就是態(tài)度問題 115 后 記 走向何方 129 附錄 A 編碼檢查表 130 附錄 B 內(nèi)存登錄例程 133 附錄 C 練習(xí)答案 140 參考文獻(xiàn) 160 (注:上述頁碼是以原書為基準(zhǔn),與本電子版本沒有什么關(guān)系) 獻(xiàn)給我的妻子 以及我的雙親 為了他們的愛和支持 序 1986年,在為幾家小公司咨詢和工作了 10 年之后為了獲得編寫 用程序的經(jīng)驗(yàn),我特意到 加了 發(fā)小組。這個小組負(fù)責(zé) 當(dāng)時,我還不能肯定想象的代碼是什么樣子的,我想也許應(yīng)該既引入入勝又雅致吧!但我看到的代碼卻很平常,與我以往見到的其它代碼沒有什么不同。要知道, 它比當(dāng)時其它基于字符的電子表格軟件更容易使用,更加直觀。但使我感受更深的是產(chǎn)品中包含的一個多功能調(diào)試系統(tǒng)。 該系統(tǒng)旨在自動地問程序員和測試者進(jìn)行錯誤報警。其工作方式非常象波音 747 駕駛倉內(nèi)向駕駛員報告故障的報警燈。該調(diào)試系統(tǒng)主要用來對代碼進(jìn)行監(jiān)視,它并不過多地對代碼進(jìn)行測試。雖然現(xiàn)在該調(diào)試系統(tǒng)采用的概念已不再新鮮了,但當(dāng)時它們的廣泛使用程度以及 4 該系統(tǒng)有效的查錯能力還是吸引了我,使我深受啟發(fā)。沒過多久,我就發(fā)現(xiàn) 錯誤及其產(chǎn)生原因。 在做了兩年 后,我離開了該開發(fā)小組,去幫助另一個代碼錯誤數(shù)目超常的小組。在開發(fā) 發(fā)現(xiàn) 許多老項(xiàng)目組熟知的概念并沒有隨著公司的壯大而傳到新項(xiàng)目組。新程序員不象我加入 只有一般的注意。 在我轉(zhuǎn)到新項(xiàng)目組六個月之后,有一次我對一個程序員伙伴提到:“應(yīng)該把編寫無錯代碼的某些概念寫成文字,使那些原理能在新項(xiàng)目組傳開”。這時另一位程序員對我說: “你不要總是想著寫文檔,為什么你不把這一切都寫下來?為什么你不寫本書,問問 竟這些信息不是誰的專利,其作用不過是為了使程序員更加重視錯誤。” 當(dāng)時我對這個建議并沒有多想,主要原因是沒有時間,而且以前我也沒有寫過書。以前我所做過與寫書最有關(guān)系的事情,不過是在 80 年代初協(xié)助別人主辦 與寫書畢竟不是一回事。 正如您所見到的,這本書還是寫出來了。理由很簡單: 1990 年,由于錯誤越來越多,消了一個尚未公布的產(chǎn)品。現(xiàn)在,錯誤越來 越多已經(jīng)不是什么新鮮事情, 是頭一次。最近,隨著接連不斷地出現(xiàn)產(chǎn)品錯誤。管理人員終于開始叫嚷“受不了啦”,并采取了一系列的措施企圖將錯誤率下降到原先的水平。盡管如此,仍然沒有人將這些錯誤因由記錄下來。 現(xiàn)在, 難設(shè)想,倘若沒有準(zhǔn)確的指南,公司怎樣才能將出錯率降低到原來的水平。尤其是在 是如此。 以上就是我最終決 定寫這本書的原因 情況就是這樣。 我希望您會喜歡這本書,我力圖使本書不那么枯燥并盡量有趣。 雅圖,華盛頓 謝 5 我要感謝 其是在我寫作過程中始終手把手地教我的兩個人。首先我要感謝我的約稿編輯 使我能夠按照自己的進(jìn)度完成了這本書,并且耐心地解答了我這個新作者提出的許多問題。我還要特別感謝我的責(zé)任編輯 士,她用了許多額外時間及早地對我寫出的章節(jié)提出了反饋意見。沒有他們的幫助,就不會有這本書。 鼓勵我以幽默的風(fēng)格寫這本書。她對文中的小俏皮話發(fā)笑當(dāng)然不會使我不快。 我還要感謝我的父親 他在 70 年代中期把我引入早期的微機(jī)世界: 我與這一行結(jié)緣。我要感謝我于 1981 83 年在 是對我職業(yè)生涯最有影響的幾個人之一,他的知識以及洞察力在本書中都有所體現(xiàn)。還有 過去的 10年里,我與他在全國各地的許多項(xiàng)目中都有過愉快的合作,他也無疑的塑造了我的思維方式。 最后感謝花時間閱讀本書草稿,并提供技術(shù)反饋意見的所有人。他們是: 別感謝們不僅是本書草稿的評審者,而且在本書內(nèi)容的構(gòu)思上對我很有幫助。 命名約定 本書采用的命名約定和 匈牙利式”命名約定差不多。該約定是由生于匈牙利布達(dá)佩斯的 通過在數(shù)據(jù)和函數(shù)名中加入額外的信息以增進(jìn)程序員對程序的理解。例如: /* 所有的字符變量均以 始 */ b; /* 所有的字節(jié)均冠以 b */ l; /* 所有的長字均冠以 l */ 對于指向某個數(shù)據(jù)類型的指針,可以先象上面那樣建立一個有類型的名字,然后給該名字加上前綴字母 P: /* 指向 */ /* 同理 */ /* 特意顯用的空指針 */ * 指向字符指針的指針 */ /* 指向字節(jié)指針的指針 */ 匈牙利式名字通常不那么好念,但在代碼中讀到它們時,確實(shí)可以從中得到許多的信息。例如,當(dāng)你眼看到某個函數(shù)里有一個名為 用查看聲明就立即知道它是一個指向字符的指針。 6 為了使匈牙利式名字的描述性更強(qiáng)或者要區(qū)分兩個變量名,可以在相應(yīng)類型派生出的基本名字之后加上一個以大寫字母開頭的 “標(biāo)簽”。例如, 個是源指針,另一個是目的指針。使用匈牙利式命名約定,其相應(yīng)的原型是: /* 原型 */ 在上面的例子中,兩個字符指針有一個共同的特點(diǎn) 都指向以 0為結(jié)尾的 此在本書中,每當(dāng)用字符指針指向字符串時,我們就用一個更有意義的名子 此,上述 /* 原型 */ 本書用到另一個類型是 面給出該類型的一些典型用法: /* 原型 */ /* 原型 */ /* 原型 */ 函數(shù)和數(shù)組的命名遵循同樣的約定,名字由相應(yīng)的返回類型名開始,后跟一個描述的標(biāo)簽。例如: /* 由變量得一字符 */ ; /* 由數(shù)組得一字符 */ /* 由函數(shù)得一字符 */ 如果利用匈牙利式命名方法, 以寫成如下形式: /* 原型 */ /* 原型 */ 由于匈牙利式命名方法旨在增進(jìn)程序員對程序的理解, 所以大多數(shù)匈牙利式名字的長度都要超過 格規(guī)定 6個字母的限制。這就不妙,除非所用的系統(tǒng)是幾十年前設(shè)計(jì)的系統(tǒng),否則這 6個字母的限制只當(dāng)是歷史的遺跡。 以上內(nèi)容基本上沒有涉及到匈牙利式命名約定的細(xì)節(jié),所介紹的都是讀者理解本書中所用變量和函數(shù)名稱意義的必需內(nèi)容。如果讀者對匈牙利式命名約定的詳細(xì)內(nèi)容感興趣,可以參考本書末尾參考文獻(xiàn)部分列出的 某些背景 本書用到了一些讀者可能不太熟悉的軟件和硬件系統(tǒng)的名稱。下面對其中最常見的幾個系統(tǒng)給出簡單的描述 司的圖形窗口計(jì)算機(jī),公布于 1984 年。它是最先支持“所見即所得”擁戶界面的流行最廣的計(jì)算機(jī)。 司的圖形窗口操作系統(tǒng)。 司1990年公布了 版本明顯好于其早期版本。 司的圖形電子表格軟件, 1985 年首次在 7 后在進(jìn)行了大量的重寫和排錯工作后,被移植到 年來 程序所用的代碼并不相同。 在本書中,找多次提到曾經(jīng)當(dāng)過 應(yīng)該說明的是,我的大部分工作是將 代碼移到 與該產(chǎn)品現(xiàn)在的驚人成功并沒有特別的關(guān)系。 我為 做的唯一真正重要的貢獻(xiàn)是說服直接利用 享用了 0%的源代碼。這對 用戶意義重大,因?yàn)橛昧?以后他們會感至 際上, 于字符并在 ; 目前為止,這三種版本的產(chǎn)品雖然是用不同的源代碼做出的,但它們非常相象 ,用戶改用任何一個都不會有什么困難。由于 經(jīng)決定 高版本也將采用共享代碼進(jìn)行開發(fā)。 80 80器常用的 680 680 引言 幾年前在一次偶然翻閱 著 書時,序言中的一段話深深觸動了我: 我確信 985年 11 月 27日 被發(fā)現(xiàn)并排除掉了。但是如果出于目前尚不知道的原因, 非常愿意付給第一個發(fā)現(xiàn)者 $。(這一金額已是以前的兩倍。我打算在本年內(nèi)再增加一倍。你看我是多么自信?。?我對 不感興趣,這并不重要。重要的是他對他的程序所具有的那種自信。那么據(jù)你所知,究竟有多少程序員會嚴(yán)肅地聲稱他們的程序完全沒有錯誤?又有多少敢把這一聲稱印刷在書上,并準(zhǔn)備為錯誤的發(fā)現(xiàn)者付錢呢? 如果程序員確信測試組已經(jīng)發(fā)現(xiàn)了所有的錯誤,那么他也許敢作這種聲明。但這本身 就是一個問題。每當(dāng)代碼被打包裝送給程序經(jīng)銷商之前,人們在胸前劃著十字帶著最好的愿望 8 說:“希望測試已經(jīng)發(fā)現(xiàn)了所有的錯誤”。這一情景我已見過多次了。 由于現(xiàn)代的程序員已經(jīng)放棄了對代碼進(jìn)行徹底測試的職責(zé),他們沒法知道代碼中是否有錯。管理人員也不會公布測試情況,只是說:“別操那個心,測試人員會為你作好測試的”。更為微妙的是,管理人員希望程序員自己進(jìn)行代碼的測試。同時,他們希望測試員作得更徹底些,因?yàn)楫吘惯@是他們的本職工作。 正如你在本書中將會看到的那樣,編寫無錯代碼的技術(shù)或許有幾百種,程序員能用,但測試人員卻無法使 用,因?yàn)檫@些技術(shù)和代碼的編寫直接相關(guān)。 兩個關(guān)鍵的問題 本書介紹的所有決竅是當(dāng)發(fā)現(xiàn)錯誤時,不斷地就以下兩個問題追問自己的結(jié)果: 怎樣才能自動地查出這個錯誤? 怎樣才能避免這個錯誤? 第一個問題可能使讀者認(rèn)為本書是有關(guān)測試的書,其實(shí)不是。當(dāng)編輯程序發(fā)現(xiàn)語法錯誤時,它是在做測試嗎?不,不是。編輯程序只是在自動地檢查代碼中的錯誤。語法錯誤只是程序員可以使用的自動查錯方法查出的一種最基本的錯誤類型。本書將詳盡介紹自動向程序員提示錯誤的方法。 編寫無錯代碼的最好方法是把防上錯誤放在第一位。關(guān)于這個問題,同樣也有許 多的技巧。某些技巧與常用的編碼慣例有關(guān),但它們不是象“每個人都違背原則”或“沒有人違背該原則”這樣泛泛地考慮問題,而是對相應(yīng)的細(xì)節(jié)進(jìn)行詳細(xì)的討論。要記住,在任何時候跟在大多數(shù)人的后面常常是所能選擇的最壞一條路。因此在成為別人的追隨者之前一定要確定這樣做確實(shí)有意義,而且不要僅僅因?yàn)槠渌氖裁慈巳绱俗约阂踩绱恕?本書的最后一章討論編寫無錯代碼應(yīng)持正確態(tài)度的重要性。如果沒有正確的態(tài)度,發(fā)現(xiàn)錯誤和防止錯誤就好比在冬季大開著窗戶給房間加熱,雖然也能達(dá)到目的,但要浪費(fèi)大量的能量。 本書除第 4章和第 8章以外都配有練習(xí)。但 要注意,這些練習(xí)并不是要測驗(yàn)讀者對相應(yīng)內(nèi)容的理解。實(shí)際上更多的是作者想在該章的正文中闡述卻沒能放進(jìn)去的要點(diǎn)。其它的練習(xí)為的是讓讀者思考與該章內(nèi)容有關(guān)的一些問題,打開思路,琢磨一下以前未曾考慮過的概念。 無論哪種情況,都是想通過練習(xí)再補(bǔ)充一些新的技巧和信息,因此值得一讀。為使讀者了解作者的意圖,本書在附錄 部分章節(jié)還給出了一些課題,但這些課題沒有答案,因?yàn)檫@種課題通常是任務(wù),而不是問題。 規(guī)則或者建議 本書的編排類似于 . J. 寫 的程序設(shè)計(jì)經(jīng)典著作 該書出于 . B. 寫的重要經(jīng)典著作 這兩本書采用同樣的基本概念表達(dá)方法: 9 給出一個例子; 指出該例子中的某些問題所在; 用一般的準(zhǔn)則改進(jìn)該例子。 確實(shí),這是個程式,而且是使讀者感到舒服的程式,因此本書同樣采用了這一程式。作者力圖使本書讀起來是一種享受,盡管它有著公式的性質(zhì)。希望讀者會覺得本書很有趣。 本書還給出一些似乎不應(yīng) 違背的“一般準(zhǔn)則”。我們的第一條準(zhǔn)則是: 由于準(zhǔn)則是用來說明一般情況的,所以本書一般并不指明準(zhǔn)則的例外情況,而把它留給讀者。我相信,當(dāng)讀者讀到某個準(zhǔn)則時,肯定會懷疑道:“噢,當(dāng)時,不是這樣的”。如果某個人對你說:“不能闖紅燈”,雖然這是一條準(zhǔn)則,但你肯定能夠舉出一種特殊情況,在這種情況下闖紅燈倒是個正確的行動。這里關(guān)鍵是要記住準(zhǔn)則只是在一般情況下才有意義,因此只有理由十分充足時,才可以違背準(zhǔn)則。 關(guān)于本書代碼的說明 本書的所有代碼都是按 寫的,并且通過了 + + 際公司 還有一個問題:如果讀者想從本書中摘取代碼用在自己的程序中,那要小心。因?yàn)闉榱苏f明書中的論點(diǎn),許多例子都有錯誤。另外,書中用到的函數(shù)雖然 名字和功能都與 的標(biāo)準(zhǔn)庫函數(shù)相同,但已對相應(yīng)的界面進(jìn)行了一些小的修改。例如 s, c, n); 這里 處理。在本書的許多地方,讀者都會看到字符類型被顯式地聲明為 不是 準(zhǔn) 將所有的字符變元都聲明為 為了保證其庫函數(shù)同樣可以用于 時程序使用 于在本書中只使用 ,所以不必考慮這些向下兼容的細(xì)節(jié)而可以用更加精確的類型聲明以改進(jìn)程序的清晰程度并用原型進(jìn)行強(qiáng)類型檢查(詳見第 1章)。 每條準(zhǔn)則都有例外 10 “提到 出于某種原因,一本書如果沒有提到 000,當(dāng)然還有 60,就不會被認(rèn)真對待。因此,我在這里也提到了它們。僅此而已,讀者在本書中再也不會見到這些字眼、讀者 見到最多的是 別還有 為近年來我一直為這些系統(tǒng)編寫代碼。但是應(yīng)該注意,本書中的任何代碼都不受這些特定的系統(tǒng)約束。它們都是用通用的 該能夠工作于任何的 編譯程序下。因此即使讀者使用的系統(tǒng)本書沒有提及,也不必?fù)?dān)心這些操作系統(tǒng)的細(xì)節(jié)會產(chǎn)生障礙。 應(yīng)該提到的是在大多數(shù)的微機(jī)系統(tǒng)中,用戶都可以通過 針進(jìn)行讀寫,破壞棧框架并在內(nèi)存甚至是其它應(yīng)用程序的內(nèi)存區(qū)中留下許多的無用信息,而硬件并沒有什么反應(yīng),聽任用戶為所 欲為。之所以提到這一點(diǎn),是因?yàn)槿绻x者習(xí)慣于認(rèn)為通過 針進(jìn)行寫操作會引起硬件故障的話,那么可能會對本書中的某些語句感到迷惑不解。遺憾的是,目前微機(jī)上的保護(hù)型操作系統(tǒng)仍不普及,破壞內(nèi)存的隱患必須通過硬件保護(hù)(通常它也不能提供充足的保護(hù))之外的方法才能發(fā)現(xiàn)。 有錯誤就有錯誤 不必為本書的讀者定義什么叫錯誤,相信讀者都知道什么是錯誤。但是錯誤可以分為兩類:一類是開發(fā)某一功能時產(chǎn)生的錯誤,另一類是在程序員認(rèn)為該功能已經(jīng)開發(fā)完成之后仍然遺留在代碼中的錯誤。 例如在 ,每個產(chǎn)品都由一些絕不 應(yīng)該含有錯誤的原版源代碼構(gòu)成。當(dāng)程序員給產(chǎn)品增加新功能時,并不直接改變相應(yīng)的原版源代碼,改變的是其副本。只有在這些改變已經(jīng)完成,并且程序員確信相應(yīng)代碼中已經(jīng)沒有錯誤時,才將其合并到原版源代碼中。因此從產(chǎn)品質(zhì)量看,在實(shí)現(xiàn)指定功能過程中不論產(chǎn)生多少個錯誤都沒有關(guān)系,只要這些錯誤在相應(yīng)代碼被并入原版源代碼之前被刪除掉就行。 所有的錯誤都有害,但損害產(chǎn)品最危險的錯誤是已經(jīng)進(jìn)入原版源代碼中的錯誤。因此,本書中提到的錯誤指的就是這些已經(jīng)進(jìn)入原版源代碼中的錯誤。作者并不指望程序員在鍵入計(jì)算機(jī)之前總是寫出沒有錯誤的代碼,但 確信防止錯誤侵入原版源代碼是完全可能的。尤其是程序員在使用了本書提供的秘訣之后,更是如此。 11 12 第 1 章 假想的編譯程序 讀者可以考慮一下倘若編譯程序能夠正確地指出代碼中的所有問題,那相應(yīng)程序的錯誤情況會怎樣?這不單指語法錯誤,還包括程序中的任何問題,不管它有多么隱蔽。例如,假定程序中有“差 1”錯誤,編譯程序可以采用某種方法將其查出,并給出如下的錯誤信息 - 3: i 2: i, i 32768 再如,當(dāng)出現(xiàn)了參數(shù)傳遞錯誤時,編譯程序可以給出如下的錯誤信息: - 18: 了,要 求編譯程序能夠做到這一程度似乎有點(diǎn)過分。但如編譯程序真能做到這些,可以想象編寫無錯程序會變得多么容易。那簡直是小事一樁,和當(dāng)前程序員的一般作法真沒法比。 假如在間諜衛(wèi)星上用攝像機(jī)對準(zhǔn)某個典型的軟件車間就會看到程序員們正弓著身子趴在鍵盤上跟蹤錯誤;旁邊,測試者正在對剛作出的內(nèi)部版本發(fā)起攻擊,輪番轟炸式地輸入人量的數(shù)據(jù)以求找出新的錯誤。你還會發(fā)現(xiàn),測試員正在檢查老版本的錯誤是否溜進(jìn)了新版本??梢酝葡?,這種查錯方法比用上面的假想編譯程序進(jìn)行查錯要花費(fèi)大得多的工作量、確實(shí)如此,而且它還要有點(diǎn)運(yùn)氣。 運(yùn)氣? 是的, 運(yùn)氣。測試者之所以能夠發(fā)現(xiàn)錯誤,不正是因?yàn)樗⒁獾搅酥T如某個數(shù)不對、某個功能沒按所期望的方式工作或者程序癱瘓這些現(xiàn)象嗎?再看看上面的假想編譯程序給出的上述錯誤:程序雖然有了“差 1”錯誤,但如果它仍能工作,那么測試者能看得出來嗎?就算看得出來,那么另外兩個錯誤呢? 這聽起來好象很可怕但測試人員就是這樣做的大量給程序輸入數(shù)據(jù),希望潛在的錯誤能夠亮相?!班蓿?!我們測試人員的工作可不這么簡單,我們還要使用代碼覆蓋工具、自動的測試集、隨機(jī)的“猴”程序、抽點(diǎn)打印或其他什么的”。也許是這樣,但還是讓我們來看看這些工具究 竟做了些什么吧!覆蓋分析工具能夠指明程序中哪些部分未被測試到,測試人員可以使用這一信息派生出新的測試用例。至于其它的工具無非都是“輸入數(shù)據(jù)、觀察結(jié)果”這一策略的自動化。 請不要產(chǎn)生誤解,我并不是說測試人員的所作所為都是錯誤的。我只是說利用黑箱方法所能做的只是往程序里填數(shù)據(jù),并看它彈出什么。這就好比確定一個人是不是瘋子一樣。問一些問題,得到回答后進(jìn)行判斷。但這樣還是不能確定此人是不是瘋子。因?yàn)槲覀儧]法知道其頭腦中在想些什么。你總會這樣地問自己:“我問的問題夠嗎?我問的問題對嗎”。 13 因此,不要光依賴黑箱測試 方法。還應(yīng)該試著去模仿前面所講的假想編譯程序,來排除運(yùn)氣對程序測試的影響,自動地抓住錯誤的每個機(jī)會。 考慮一下所用的語言 你最后一次看推銷字處理程序的廣告是什么時候?如果那個廣告是麥迪遜大街那伙人寫的,它很可能是這么說:“無論是給孩子們的老師寫便條還是為下期的 稿, 能行,毫不費(fèi)勁! 備了令人吃驚的 233000 字的拼寫字典,足足比同類產(chǎn)品多 51000個字。它可以方便地找出樣稿中的打字錯誤。趕快到經(jīng)銷商那里去買一份拷貝。 。 用戶經(jīng)過不斷地市場宣傳熏陶,差不多都相信拼寫字典越大越好,但事實(shí)并非如此。象些詞,在任何一本簡裝字典中都可以查到、但在 是拼寫正確的詞嗎?如果是,那么當(dāng)你看到我寫的 本意很可能是與之風(fēng)馬牛不相及的 題不在于 幸運(yùn)的是,某些質(zhì)量比較高的拼寫檢查程序允許用戶刪去象 樣一來,拼寫檢查程序就可以把原來合法的單詞看成是拼寫錯誤。好的編譯程序也應(yīng)該能夠這樣 可以把屢次出錯的合法的 如,這類編譯程序能夠檢查出以下 /* 制一個不重疊的內(nèi)存塊 */ ( ( * = *; 我們從程序的縮進(jìn)情況就可以知道 編譯程序卻認(rèn)為這是一個完全合法的 循環(huán)體為空語句。由于有時需要空語句,有時不需要空語句,所以為了查出不需要的空語句,編譯程序常常在遇到空語句時給出一條可選的警告信息,自動警告你可能出了上面的錯誤。當(dāng)確定需要用空語句時,你就用。但最好用如: = *) 14 由于 表達(dá)式,所以這個程序沒有間題。使用 為 樣,編譯程序接受顯式的 句,但把隱式空語句自動地當(dāng)作錯誤標(biāo)出。在程序中只允許使用一種形式的空語句,如同為了保持文字的一致性,文中只想使用 數(shù)形式 此要從拼寫字典中刪除另一種復(fù)數(shù)形式 另一個常見的問題是無意的賦值。 允許在任何可以使用表達(dá)式的地方使用賦值語句。因此如果用戶不夠謹(jǐn)慎,這種多余的靈活性就會使你犯錯誤。例如,以下程序就出現(xiàn)了這種常見的錯誤: if( t ) ; 雖然很清楚該程序是要將 實(shí)際上卻成了對 賦值。對于這種程序,編譯程序當(dāng)然不會產(chǎn)生錯誤,因?yàn)榇a是合法的 C。 某些編譯程序允許用戶在 & 和 | | 表達(dá)式以及 造的控制表達(dá)式中禁止使用簡單賦值,這樣就可以幫助用戶查出這種錯誤。這種做法的基本依據(jù)是用戶極有可能在以上五種情況下將等號偶然地健入為賦值號。 這種選擇項(xiàng)并不妨礙用戶作賦值,但是為了避免產(chǎn)生警告信息,用戶必須再拿別的值,如零或空字符與賦值結(jié)果做顯式的比較。因此,對于前面的 循環(huán)寫成: = *) 編譯程序會產(chǎn)生警告信息一所以要寫成; (* = *)!= 0 ) 這樣做有兩個好處。第一,現(xiàn)代的商用級編譯程序不會為這種冗余的比較產(chǎn)生額外的代碼,可以將其優(yōu)化掉。因此,提供這種警告選擇項(xiàng)的編譯程序是可以信賴的。第二,它可以少冒風(fēng)險,盡管兩種都合法,但這是更安全的用法。 另一類錯誤可以被歸入“參數(shù)錯誤”之列。例如,多年以前,當(dāng)我正在學(xué) 經(jīng)這樣調(diào)用過 “ to s. n” , n ); 這一程序看起 來好象沒有問題,但 知道為什么,我一直認(rèn)為流指針( 是這類流函數(shù)的第一個參數(shù)。事實(shí)并非如此,所以我常常給這些函數(shù)傳遞過去許多沒用的信息。幸好 提供了函數(shù)原型,能在編譯時自動地查出這些錯誤。 由于 標(biāo)準(zhǔn)要求每個庫函數(shù)都必須有原型所以在 文件中能夠找到 15 原型。 c, 如果在程序中 么在調(diào)用 譯程序會根據(jù)其原 型對所傳遞的每個參數(shù)進(jìn)行比較。如果二者類型不同,就會產(chǎn)生編譯錯誤。在上面的錯誤例于中,因?yàn)樵?類型的參數(shù),所以利用原型可以自動地發(fā)現(xiàn)前一個 雖然要求標(biāo)準(zhǔn)的庫函數(shù)必須有原型,但并不要求用戶編寫的函數(shù)也必須有原型。嚴(yán)格地說,它們可以有原型,也可以沒有原型。如果用戶想要檢查出自己程序中的調(diào)用錯誤,必須自己建立原型,并隨時使其與相應(yīng)的函數(shù)保持一致。 最近我聽到程序員在抱怨他們必須對函數(shù)的原型進(jìn)行維護(hù)。尤其是剛從傳統(tǒng) 項(xiàng)目時,這種抱怨更多 。這種抱怨是有一定理由的,但如果不用原型,就不得不依賴傳統(tǒng)的測試方法來查出程序中的調(diào)用錯誤。你可以捫心自問,究竟哪個更重要,是減少一些維護(hù)工作量,還是在編譯時能夠查出錯誤?如果你還不滿意,請?jiān)倏紤]一下利用原型可以生成質(zhì)量更好的代碼這一事實(shí)。這是因?yàn)椋?標(biāo)準(zhǔn)使得編譯程序可以根據(jù)原型信息進(jìn)行相應(yīng)的優(yōu)化。 在傳統(tǒng) 于不在當(dāng)前正被編譯的文件中的函數(shù),編譯程序基本上得不到關(guān)于它的信息。盡管如此,編譯程序仍然必須生成對這些函數(shù)的調(diào)用,而且所生成的調(diào)用必須奏效。 編譯程序?qū)崿F(xiàn)者解 決這個問題的辦法是使用標(biāo)準(zhǔn)的調(diào)用約定。這一方法雖然奏效,但常常意味著編譯程序必須生成額外的代碼,以滿足調(diào)用約定的要求。但如果使用了“要求所有函數(shù) 都必須有原型”這一編譯程序提供的警告選擇項(xiàng),由于編譯程序了解程序中每個函數(shù)的參數(shù)情況,所以可以為不同的函數(shù)選擇它認(rèn)為最有效率的調(diào)用約定。 空語句、錯誤的賦值以及原型檢查只是許多 C 編譯程序提供的選擇項(xiàng)中的一小部分內(nèi)容,實(shí)際上常常還有更多的其它選擇項(xiàng)。這里的要點(diǎn)是:用戶可以選擇的編譯程序警告設(shè)施可以就可能的錯誤向用戶發(fā)出警告信息,其工作的方式 非常類似于拼寫檢查程序?qū)赡艿钠磳戝e誤的處理 說是 80年代最好的合股投資公司管理者,他曾經(jīng)說過:投資者與賭徒之間的區(qū)別在于投資者利用每一次機(jī)會,無論它是多么小,去爭取利益;而賭徒則只靠運(yùn)氣。用戶應(yīng)該將這一概念同樣應(yīng)用于編程活動,選擇編譯程序的所有可選警告設(shè)施,并把這些措施看成是一種無風(fēng)險高償還的程序投資。再不要問:“應(yīng)該使用這一警告設(shè)施嗎?而應(yīng)該問:“為什么不使用這一警告設(shè)施呢?”。要把所有的警告開關(guān)都打開,除非有極好的理由才不這樣做。 增強(qiáng)原型的能力 不幸的是,如果函數(shù)有 兩個參數(shù)的類型相同,那么即使在調(diào)用該函數(shù)時互換了這兩個參使用編譯程序所有的可選警告設(shè)施 16 數(shù)的位置,原型也查不出這一調(diào)用錯誤。例如,如果函數(shù) 那么在調(diào)用該函數(shù)時,即使互換其字符 譯程序也不會發(fā)出警告信息。但是如果在相應(yīng)界面和原型中使用了更加精確的類型,就可以增強(qiáng)原型提供的錯誤檢查能力。例如,如果有了下面的原型: 那么在調(diào)用該函數(shù)時弄反了其字符 譯程序就會給出警告錯誤。 在原型中使用更精確類型的缺陷是常常必須進(jìn)行參數(shù)的顯式類型轉(zhuǎn)換,以消除類型不匹配的錯誤,即使參數(shù)的次序正確。 不那么差 另一種檢查錯誤更詳細(xì)、更徹底的方法是使用 種方法幾乎不費(fèi)什么事。最初,個工具用來掃描 C 源文件并對源程序中不可移植的代碼提出警告。但是現(xiàn)在大多數(shù)用程序已經(jīng)變得更加嚴(yán)密,它不但可以檢查出可移植性問題,而且可以檢查出那些雖然可移植并且完 全合乎語法但卻很可能是錯誤的特性,上一節(jié)那些可疑的錯誤就屬于這一類。 不幸的是,許多程序員至今仍然把 作是一個可移植性的檢查程序,認(rèn)為它只能給出一大堆無關(guān)的警告信息??傊?到了不值得麻煩的名聲。如果你也是這樣想的程序員,那么你也許應(yīng)該重新考慮你的見解。想一想究竟是哪一種工具更加接近于前文所述的假想編譯程序,是你正使用的編譯程序,還是 實(shí)際上,一旦源程序變成了沒有 誤的形式,繼續(xù)使其保持這種狀態(tài)是很容易做到的。只要對所改變的部分運(yùn)行 有錯誤之后再把其并入到原版源代 碼中即可。利用這種方法,并不要進(jìn)行太多的考慮,只要經(jīng)過一、二周就可以寫出沒有 誤的代碼。在達(dá)到這個程度時,就可以得到 但我做的修改很平常 一次在同本書的一個技術(shù)評審者共進(jìn)午餐時,他問我本書是否打算包括一節(jié)單元測試方面的內(nèi)容。我回答說:“不”。因?yàn)楸M管單元測試也與無錯代碼的編寫有關(guān),但它實(shí)際上屬于另一個不同的類別,即如何為程序編寫測試程序。 他說:“不,你誤解了。我的意思是你是否打算指出在將新做的修改并入原版源代碼之前,程序員應(yīng)該實(shí)際地進(jìn)行相應(yīng)的單元測試。我的小組中 的一位程序員就是因?yàn)樵谶M(jìn)行了程序的修改之后沒有進(jìn)行相應(yīng)的單元測試,使一個錯誤進(jìn)入到我們的原版源代碼中?!?這使我感到很驚奇。因?yàn)樵?多數(shù)項(xiàng)目負(fù)責(zé)人都要求程序員在合并修改了使用 查出編譯程序漏掉的錯誤 17 的源代碼之前,要進(jìn)行相應(yīng)的單元測試。 “你沒問他為什么不做單元測試嗎?”,我問道。 我的朋友從餐桌上抬起頭來對我說:“他說他并沒有編寫任何新的代碼,只是對現(xiàn)有代碼進(jìn)行了某些移動。他說他認(rèn)為沒必要再進(jìn)行單元測試”。 這種事情在我的小組中也曾經(jīng)發(fā)生過。 它使我想起曾經(jīng)有一個程序員在進(jìn)行了修改之后,甚至沒有再編譯一次就把相應(yīng)的 代碼并入了原版源代碼中。當(dāng)然,我發(fā)現(xiàn)了這一問題,因?yàn)槲以趯υ嬖创a進(jìn)行編譯時產(chǎn)生了錯誤。當(dāng)我問這個程序員怎么會漏掉這個編譯錯誤,他說:“我做的修改很平常,我認(rèn)為不會出錯”,但他錯了。 這些錯誤本來都應(yīng)該不會進(jìn)入原版源代碼中,因?yàn)槎叨伎梢詭缀鹾敛毁M(fèi)力地被查出來。為什么程序員會犯這種錯誤呢?是他們過高地估計(jì)了自己編寫正確代碼的能力。 有時,似乎可以跳過一些設(shè)計(jì)用來避免程序出錯的步驟,但走捷徑之時,就是麻煩將至之日。我懷疑會有許多的程序員甚至沒有對相應(yīng)的代碼進(jìn)行編譯,就“完成”了某一功能。我知道這只是偶然情況 ,但繞過單元測試的趨勢正在變強(qiáng),尤其是作簡單的改動。 如果你發(fā)現(xiàn)自己正打算繞過某個步驟。而它恰恰可以很容易地用來查錯,那么一定要阻止自己繞過。相反,要利用所能得到的每個工具進(jìn)行查錯。此外,單元測試雖然意味著查錯,但如果你根本就不進(jìn)行單元測試也是枉然。 小結(jié) 你認(rèn)識哪個程序員寧愿花費(fèi)時間去跟蹤排錯,而不是編寫新的代碼?我肯定有這種程序員,但至今我還沒有見過一個。對于我認(rèn)識的程序員,如果你答應(yīng)他們再不用跟蹤下一個錯誤,他們會寧愿一輩子放棄享用中國菜。 當(dāng)你寫程序時,要在心中時刻牢記著假想編譯程序這一概念 ,這樣就可以毫不費(fèi)力或者只費(fèi)很少的力氣利用每個機(jī)會抓住錯誤。要考慮編譯程序產(chǎn)生的錯誤、 生的錯誤以及單元測試失敗的原因。雖然使用這些工具要涉及到很多的特殊技術(shù),但如果不花這么多的功夫,那產(chǎn)品中會有多少個錯誤? 如果想要快速容易地發(fā)現(xiàn)錯誤,
溫馨提示
- 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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2026年智能電表在電氣節(jié)能中的經(jīng)濟(jì)分析
- 急診護(hù)理管理與應(yīng)急處理技巧
- 醫(yī)療急救現(xiàn)場禮儀與應(yīng)急處置
- 醫(yī)療行業(yè)醫(yī)院文化建設(shè)要點(diǎn)
- 2026年湖南科技職業(yè)學(xué)院高職單招職業(yè)適應(yīng)性測試備考試題有答案解析
- 2026年河南應(yīng)用技術(shù)職業(yè)學(xué)院單招綜合素質(zhì)考試模擬試題帶答案解析
- 賬戶管理辦法培訓(xùn)課件
- 護(hù)理創(chuàng)新技術(shù)與產(chǎn)品研發(fā)進(jìn)展
- 護(hù)理專業(yè)認(rèn)證與醫(yī)院護(hù)理質(zhì)量提升
- 2026年河北軌道運(yùn)輸職業(yè)技術(shù)學(xué)院單招綜合素質(zhì)筆試備考題庫帶答案解析
- 《道路旅客運(yùn)輸企業(yè)突發(fā)事件應(yīng)急預(yù)案》
- 阿拉伯語課程講解
- 噴油部管理制度
- 《齊魯文化》期末筆記
- 非煤地下礦山機(jī)電知識
- 化工原理課程設(shè)計(jì)說明書-2778kg-h苯-甲苯篩板式精餾塔設(shè)計(jì)
- 97S501-1-井蓋及踏步圖集
- GB 30254-2024高壓三相籠型異步電動機(jī)能效限定值及能效等級
- 鹽酸、硫酸產(chǎn)品包裝說明和使用說明書
- 汽車線束DFMEA設(shè)計(jì)失效模式和影響分析
- plc電梯設(shè)計(jì)的參考文獻(xiàn)
評論
0/150
提交評論