www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 公眾號(hào)精選 > 小麥大叔
[導(dǎo)讀]點(diǎn)擊上方“小麥大叔”,選擇“置頂/星標(biāo)公眾號(hào)”福利干貨,第一時(shí)間送達(dá)什么是防御性編程?防御性編程是一種細(xì)致、謹(jǐn)慎的編程方法。為了開發(fā)可靠的軟件,我們要設(shè)計(jì)系統(tǒng)中的每個(gè)組件,以使其盡可能地“保護(hù)”自己。我們通過明確地在代碼中對(duì)設(shè)想進(jìn)行檢查,擊碎了未記錄下來的設(shè)想。這是一種努力,防止...

什么是防御性編程?

防御性編程是一種細(xì)致、謹(jǐn)慎的編程方法。為了開發(fā)可靠的軟件,我們要設(shè)計(jì)系統(tǒng)中的每個(gè)組件,以使其盡可能地“保護(hù)”自己。


我們通過明確地在代碼中對(duì)設(shè)想進(jìn)行檢查,擊碎了未記錄下來的設(shè)想。這是一種努力,防止(或至少是觀察)我們的代碼以將會(huì)展現(xiàn)錯(cuò)誤行為的方式被調(diào)用。


防御性編程是一種編程習(xí)慣,是指預(yù)見在什么地方可能會(huì)出現(xiàn)問題,然后創(chuàng)建一個(gè)環(huán)境來測(cè)試錯(cuò)誤,當(dāng)預(yù)見的問題出現(xiàn)的時(shí)候通知你,并執(zhí)行一個(gè)你指定的損害控制動(dòng)作,如停止程序執(zhí)行,將用戶重指向到一個(gè)備份的服務(wù)器,或者開啟一個(gè)你可以用來診斷問題的調(diào)試信息。


這些防御性編程環(huán)境通常的構(gòu)造方法有:添加聲明到代碼中,執(zhí)行按契約進(jìn)行設(shè)計(jì),開發(fā)軟件防御防火墻,或者簡(jiǎn)單添加用來驗(yàn)證用戶輸入的代碼。


防御性編程使我們可以盡早發(fā)現(xiàn)較小的問題,而不是等到它們發(fā)展成大的災(zāi)難的時(shí)候才發(fā)現(xiàn)。


你常??梢钥吹健奥殬I(yè)”的開發(fā)人員不假思索飛快地編寫著代碼。他們開發(fā)軟件的過程可能是這樣的:


他們不斷地受到那些從未有時(shí)間驗(yàn)證的錯(cuò)誤的打擊。這很難說是現(xiàn)代軟件工程的進(jìn)步,但它卻不斷地發(fā)生著。防御性編程幫助我們從一開始就編寫正確的軟件,而不再需要經(jīng)歷“編寫-嘗試-編寫-嘗試……”的循環(huán)過程。在采用了防御性編程之后,開發(fā)軟件的過程將變成:


當(dāng)然,防御性編程并不能排除所有的程序錯(cuò)誤。但是問題所帶來的麻煩將會(huì)減少,并易于修改。防御性程序員只是抓住飄落的雪花,而不是被埋葬在錯(cuò)誤的雪崩中。


防御性編程是一種防衛(wèi)方式,而不是一種補(bǔ)救形式。我們可以將其與在錯(cuò)誤發(fā)生之后再來改正錯(cuò)誤的調(diào)試比較一下。調(diào)試就是如何來找到補(bǔ)救的辦法。


對(duì)防御性編程的誤解

關(guān)于防御性編程,有一些常見的誤解。防御性編程并不是:


檢查錯(cuò)誤

如果代碼中存在可能出現(xiàn)錯(cuò)誤的情況,無論如何你都應(yīng)該檢查這些錯(cuò)誤。這并不是防御性編碼。它只是一種好的做法,是編寫正確代碼的一部分。


測(cè)試

測(cè)試你的代碼并不是防御,而只是開發(fā)工作的另一個(gè)典型部分。測(cè)試工作不是防御性的,這項(xiàng)工作可以驗(yàn)證代碼現(xiàn)在是正確的,但不能保證代碼在經(jīng)歷將來的修改之后不會(huì)出錯(cuò)。即便是擁有了世界上最好的測(cè)試工具,也還是會(huì)有人對(duì)代碼進(jìn)行更改,并使代碼進(jìn)入過去未測(cè)試的狀態(tài)。


調(diào)試

在調(diào)試期間,你可以添加一些防御性代碼,不過調(diào)試是在程序出錯(cuò)之后進(jìn)行的。防御性編程首先是“防止”程序出錯(cuò)的措施(或在錯(cuò)誤以不可理解的方式出現(xiàn)之前發(fā)現(xiàn)它們,不然就需要整夜的調(diào)試)。


防御性編程真的值得我們來討論嗎?下面是一些支持和反對(duì)的意見:


反對(duì)意見


防御性編程消耗了程序員和計(jì)算機(jī)的資源。


  • 它降低了代碼的效率;即使是很少的額外代碼也需要一些額外的執(zhí)行時(shí)間。對(duì)于一個(gè)函數(shù)或一個(gè)類,這也許還不要緊,但是如果一個(gè)系統(tǒng)由10萬個(gè)函數(shù)組成,問題就變得嚴(yán)重了。


  • 每種防御性的做法都需要一些額外的工作。為什么要做這些工作呢?你需要做的已經(jīng)夠多的了,不是嗎?只要確保人們正確地使用你的代碼就可以了。如果他們使用的方式不正確,那么任何問題也都是他們自己造成的。


支持意見


反駁很有說服力。


  • 防御性編程可以節(jié)省大量的調(diào)試時(shí)間,使你可以去做更有意義的事情。還記得墨菲嗎:凡是可能會(huì)被錯(cuò)誤地使用的代碼,一定會(huì)被錯(cuò)誤地使用。


  • 編寫可以正確運(yùn)行、只是速度有些慢的代碼,要遠(yuǎn)遠(yuǎn)好過大多數(shù)時(shí)間都正常運(yùn)行、但是有時(shí)候會(huì)崩潰的代碼(顯示器閃爍高亮彩色火花)。


  • 我們可以設(shè)計(jì)一些在版本構(gòu)建中物理移除的防御性代碼,以解決性能問題??傊?,我們這里所考慮的大部分防御性措施,并不具有任何明顯的開銷。


  • 防御性編程避免了大量的安全性問題,這在現(xiàn)代軟件開發(fā)中是一個(gè)重大的問題。避免這些問題可以帶來很多好處。


由于市場(chǎng)要求軟件的開發(fā)更加快速和廉價(jià),我們就需要致力于實(shí)現(xiàn)這一目標(biāo)的技術(shù)。不要跳過眼前的這些額外工作,它們可以防止將來的痛苦和項(xiàng)目延遲。


防御性編程有助于程序的安全性,可以防范諸如此類惡意的濫用。黑客和病毒制造者常常會(huì)利用那些不嚴(yán)謹(jǐn)?shù)拇a,以控制某個(gè)應(yīng)用程序,然后實(shí)施他們蓄意的破壞計(jì)劃。這對(duì)軟件開發(fā)的現(xiàn)代世界而言,無疑是個(gè)嚴(yán)重的威脅;這個(gè)問題涉及到諸如生產(chǎn)效率、金錢和個(gè)人隱私等方方面面。


軟件濫用者形形色色,從利用程序小缺陷的不守規(guī)則的用戶,到想盡辦法非法進(jìn)入他人系統(tǒng)的職業(yè)黑客。有太多的程序員在不經(jīng)意間為這些人留下了可隨意通過的后門。隨著網(wǎng)絡(luò)化計(jì)算機(jī)的興起,粗心大意所帶來的后果變得愈來愈顯著了。


許多大型軟件開發(fā)公司終于意識(shí)到了這種威脅,開始認(rèn)真思考這個(gè)問題,將時(shí)間和資源投入到嚴(yán)謹(jǐn)?shù)姆烙跃幋a工作中。事實(shí)上,在受到惡意進(jìn)攻之后才亡羊補(bǔ)牢是很困難的。


在防御性編程的大框架之下,有許多常識(shí)性的規(guī)則。


人們?cè)谙氲椒烙跃幊痰臅r(shí)候,通常都會(huì)想到“斷言”,這沒有錯(cuò)。


我們將在后面對(duì)此進(jìn)行討論。但是,還是有一些簡(jiǎn)單的編程習(xí)慣可以極大地提高代碼的安全性。


盡管看上去像是常識(shí),但是這些規(guī)則卻往往被人們忽視,這就是為什么世界上并不缺少低質(zhì)量軟件的原因。只要程序員們警惕起來,受到足夠的督促,更高的安全性和可靠的開發(fā)很容易就能夠?qū)崿F(xiàn)。


在下面的幾頁中,將列出防御性編程的一些規(guī)則。我們將先從粗略的概覽開始,整體地描述防御的技巧、過程和步驟。隨著討論的深入,我們會(huì)加入更多的細(xì)節(jié),進(jìn)一步地逐條分析每條代碼語句。在這些防御性技巧中,有一些是與具體的編程語言相關(guān)的。這很自然——如果你的編程語言會(huì)讓你射傷到自己的腳,那么你一定要穿上防彈靴。


在閱讀這些規(guī)則時(shí),請(qǐng)對(duì)你自己進(jìn)行一個(gè)評(píng)估。


  • 在這些規(guī)則中,現(xiàn)在你遵循的有幾條?
  • 你打算采納那些規(guī)則?

1 使用好的編碼風(fēng)格和合理的設(shè)計(jì)

我們可以通過采用良好的編程風(fēng)格,來防范大多數(shù)編碼錯(cuò)誤。這與本篇的其他章節(jié)自然地吻合。很多簡(jiǎn)單的事,如選用有意義的變量名,或者審慎地使用括號(hào),都可以使編碼變得更加清晰明了,并減少缺陷出現(xiàn)的可能性。


同樣地,在投入到編碼工作中之前,先考慮大體的設(shè)計(jì)方案,這也非常關(guān)鍵?!白詈玫挠?jì)算機(jī)程序的文本是結(jié)構(gòu)清晰的。”(見參考書目Kernighan Plaugher 78)從實(shí)現(xiàn)一套清晰的API、一個(gè)邏輯系統(tǒng)結(jié)構(gòu)以及一些定義良好的組件角色與責(zé)任開始入手,將使你避免以后處處頭疼的局面。


2 不要倉促地編寫代碼

閃電式的編程太常見了。使用這種編程方式的程序員會(huì)很快地開發(fā)出一個(gè)函數(shù),馬上把這個(gè)函數(shù)交給編譯器來檢查語法,接著運(yùn)行一遍看看能不能用,然后就進(jìn)入下一個(gè)任務(wù)。這種方式充滿了危險(xiǎn)。


相反,在寫每一行時(shí)都三思而后行??赡軙?huì)出現(xiàn)什么樣的錯(cuò)誤?你是否已經(jīng)考慮了所有可能出現(xiàn)的邏輯分支?放慢速度,有條不紊的編程雖然看上去很平凡,但這的確是減少缺陷的好辦法。


關(guān)鍵概念 欲速則不達(dá)。每敲一個(gè)字,都要想清楚你要輸入的是什么。


在C語言中,有一個(gè)會(huì)使追求速度的程序員犯錯(cuò)的陷阱,即將“==”錯(cuò)誤地輸入為“=”。前者為相等關(guān)系測(cè)試,而后者則是變量賦值。如果你的編譯器功能不全(或者關(guān)閉了警告功能),你就不會(huì)得到相關(guān)提示,也就無從得知自己輸入了不該輸入的東西。


一定要在完成與一個(gè)代碼段相關(guān)的所有任務(wù)之后,再進(jìn)入下一個(gè)環(huán)節(jié)。例如,如果你決定先編寫主體部分,再加入錯(cuò)誤檢查和處理,那么一定要確保這兩項(xiàng)工作的完成都遵循章法。如果你要推遲錯(cuò)誤檢查的編寫,而直接開始編寫超過三個(gè)代碼


段的主體部分,你一定要慎之又慎。你也許真的想隨后再回來編寫錯(cuò)誤檢查,但卻一而再再而三地向后推遲,這期間你可能會(huì)忘記很多上下文,使得接下來的工作更加耗時(shí)和瑣碎。(當(dāng)然,到時(shí)候你還要面臨一些人為設(shè)置的最后截止日期。)


遵循章法是一種習(xí)慣,需要牢記于心并切實(shí)貫徹。如果你不立即做正確的事,那么將來你很可能也不會(huì)再去做正確的事?,F(xiàn)在就行動(dòng),不要等到撒哈拉沙漠下雨了才行動(dòng)。晚做不如早做,因?yàn)閷碓僮鰧⑿枰裱嗟恼路ā?


3 不要相信任何人

媽媽曾告訴過你,不要和陌生人說話。不幸的是,要想開發(fā)一個(gè)好的軟件,就需要更加憤世嫉俗,對(duì)人的天性更加不信任。即便是沒有惡意的代碼用戶,也可能會(huì)給你的程序帶來麻煩。防御意味著不能相信任何人。


下面這些情況可能是給你帶來麻煩的原因:


  • 真正的用戶 意外地提供了假的輸入,或者錯(cuò)誤地操作了程序;


  • 惡意的用戶 故意造成不好的程序行為;


  • 客戶端代碼 使用錯(cuò)誤的參數(shù)調(diào)用了你的函數(shù),或者提供了不一致的輸入;


  • 運(yùn)行環(huán)境 沒有為程序提供足夠的服務(wù);


  • 外部程序庫 運(yùn)行失誤,不遵從你所依賴的接口協(xié)議。


你甚至可能會(huì)在編寫一個(gè)函數(shù)時(shí)犯下愚蠢的錯(cuò)誤,或者錯(cuò)誤地使用三年前編寫的代碼,因?yàn)槟阃浟诉@些代碼究竟是怎樣運(yùn)行的。不要設(shè)想所有的一切都運(yùn)行良好,或者所有的代碼都會(huì)正確地運(yùn)行。在你的程序各處都添加安全檢查。時(shí)刻注意弱點(diǎn),用更多的防御性代碼防止弱點(diǎn)的出現(xiàn)。


關(guān)鍵概念 不要相信任何人毫無疑問,任何人(包括你自己)都可能把缺陷引入你的程序邏輯當(dāng)中。用懷疑的眼光審視所有的輸入和所有的結(jié)果,直到你能證明它們是正確的時(shí)為止。


4 編碼的目標(biāo)是清晰,而不是簡(jiǎn)潔

如果要你從簡(jiǎn)潔(但是有可能讓人困惑)的代碼和清晰(但是有可能比較冗長(zhǎng))的代碼中選擇,一定要選那些看上去和預(yù)期相符合的代碼,即使它不太優(yōu)雅。例如,將復(fù)雜的代數(shù)運(yùn)算拆分為一系列單獨(dú)的語句,使邏輯更清晰。


想一想,誰會(huì)是你的代碼的讀者。這些代碼也許需要一位初級(jí)程序員來進(jìn)行維護(hù),如果他不能理解代碼的邏輯,那么他肯定會(huì)犯一些錯(cuò)誤。復(fù)雜的結(jié)構(gòu)或不常用的語言技巧可以證明你在運(yùn)算符優(yōu)先級(jí)方面淵博的知識(shí),但是這些實(shí)際上會(huì)扼殺代碼的可維護(hù)性。請(qǐng)保持代碼簡(jiǎn)單。


不能維護(hù)的代碼是不安全的。舉一個(gè)極端的例子,過于復(fù)雜的表達(dá)式會(huì)使編譯器生成錯(cuò)誤的代碼,許多編譯器優(yōu)化的錯(cuò)誤就是因此而造成的。


關(guān)鍵概念 簡(jiǎn)單就是一種美。不要讓你的代碼過于復(fù)雜。


5 不要讓任何人做他們不該做的修補(bǔ)工作

內(nèi)部的事情就應(yīng)該留在內(nèi)部。私人的東西就應(yīng)該用鎖和鑰匙保管起來。不要把你的代碼初稿示于眾人。不管你多么禮貌地懇求,只要你稍不注意,別人就會(huì)篡改你的數(shù)據(jù),然后自以為是地試著調(diào)用“僅用于執(zhí)行”的例行程序。不要讓他們這樣做。


— 在面向?qū)ο蟮恼Z言中,通過將屬性設(shè)為專用(private)來防止對(duì)內(nèi)部類數(shù)據(jù)的訪問。在C 中,可以考慮使用Cheshire cat/pimpl idiom。(見參考書目Meyers 97)


— 在過程語言中,你仍然可以使用面向?qū)ο螅╫o)的打包概念,將private數(shù)據(jù)打包在不透明的類型背后,并提供可以操作它們的定義良好的公共函數(shù)。


— 將所有變量保持在盡可能小的范圍內(nèi)。不到萬不得已,不要聲明全局變量。如果變量可以聲明為函數(shù)內(nèi)的局部變量,就不要在文件范圍上聲明。如果變量可以聲明為循環(huán)體內(nèi)的局部變量,就不要在函數(shù)范圍上聲明。


說說“何時(shí)”


何時(shí)進(jìn)行防御性編程?你是否在事情不順利時(shí)才開始這樣做?或者在整理一些你不理解的代碼時(shí)才開始?


不,這是不對(duì)的,你應(yīng)該從始到終地使用這些防御性編程的技巧。它們應(yīng)該成為你的第二天性。成熟的程序員已經(jīng)從經(jīng)驗(yàn)中得到教訓(xùn),在吃過不止一遍的苦頭之后,他們才明白了增加預(yù)防措施是明智的。


在開始編寫代碼時(shí)就應(yīng)用防御性策略,比改進(jìn)代碼時(shí)才應(yīng)用要容易得多。如果你很晚才試著將這些策略強(qiáng)加進(jìn)去,就不可能做到萬無一失。如果你在問題出現(xiàn)后才開始添加防御性代碼,實(shí)際上你是在調(diào)試,被動(dòng)地做出反應(yīng),而不是積極地防患于未然。


然而,在調(diào)試的過程中,甚至在添加新的功能時(shí),你將發(fā)現(xiàn)一些你希望驗(yàn)證的情況。這常常是添加防御性代碼的好時(shí)機(jī)。


6 編譯時(shí)打開所有警告開關(guān)

大多數(shù)語言的編譯器都會(huì)在你“傷了它們感情的時(shí)候”給出一大堆錯(cuò)誤信息。當(dāng)這些編譯器碰到潛在的有缺陷代碼時(shí)(如在賦值之前使用C或C 變量)[3],它們也會(huì)給出各種各樣的警告。通常情況下,這些警告可以有選擇地啟用或禁用。


如果你的代碼中充滿了危險(xiǎn)的構(gòu)造,你將會(huì)得到數(shù)頁的警告信息。糟糕的是,通常的反應(yīng)是禁用編譯器的警告功能,或者干脆不理會(huì)這些信息。這兩種做法都不可取。


在任何情況下都要打開你的編譯器的警告功能。如果你的代碼產(chǎn)生了任何的警告信息,立即修正代碼,讓編譯器的報(bào)錯(cuò)聲停下來。在啟用了警告功能之后,不要對(duì)不能安靜地完成編譯的代碼感到滿意。警告的出現(xiàn)總是有原因的。即使你認(rèn)為某個(gè)警告無關(guān)緊要,也不要置之不理。否則,總有一天這個(gè)警告會(huì)隱藏一個(gè)確實(shí)重要的警告。


關(guān)鍵概念 編譯器的警告可以捕捉到許多愚蠢的編碼錯(cuò)誤。在任何情況下都啟用它們。確保你的代碼可以安安靜靜地完成編譯。


7 使用靜態(tài)分析工具

編輯器警告是對(duì)代碼的一次有限的靜態(tài)分析(即在程序運(yùn)行之前執(zhí)行的代碼檢查)的結(jié)果。


還有許多獨(dú)立的靜態(tài)分析工具可供使用,如用于C語言的lint(以及更多新出的衍生工具)和用于.NET匯編程序的FxCop。你的日常編程工作,應(yīng)該包括使用這些工具來檢查你的代碼。它們會(huì)比你的編譯器挑出更多的錯(cuò)誤。


8 使用安全的數(shù)據(jù)結(jié)構(gòu)

如果你做不到,那么就安全地使用危險(xiǎn)的數(shù)據(jù)結(jié)構(gòu)。


最常見的安全隱患大概是由緩沖溢出引起的。緩沖溢出是由于不正確地使用固定大小的數(shù)據(jù)結(jié)構(gòu)而造成的。如果你的代碼在沒有檢查一個(gè)緩沖的大小之前就寫入這個(gè)緩沖,那么寫入的內(nèi)容總是有可能會(huì)超過緩沖的末尾的。


這種情況很容易出現(xiàn),如下面這一小段C語言代碼所示:


char *unsafe_copy(const char *source)
{
char *buffer = new char[10];

strcpy(buffer, source);

return buffer;

}
如果source中數(shù)據(jù)的長(zhǎng)度超過10個(gè)字符,它的副本就會(huì)超出buffer所保留內(nèi)存的末尾。隨后,任何事都可能會(huì)發(fā)生。數(shù)據(jù)出錯(cuò)是最好情況下的結(jié)果——一些其他數(shù)據(jù)結(jié)構(gòu)的內(nèi)容會(huì)被覆蓋。而在最壞的情況下,惡意用戶會(huì)利用這個(gè)簡(jiǎn)單的錯(cuò)誤,把可執(zhí)行代碼加入到程序堆棧中,并使用它來任意運(yùn)行他自己的程序,從而劫持了計(jì)算機(jī)。這類缺陷常常被系統(tǒng)黑客所利用,后果極其嚴(yán)重。


避免由于這些隱患而受到攻擊其實(shí)很簡(jiǎn)單:不要編寫這樣的糟糕代碼!使用更安全的、不允許破壞程序的數(shù)據(jù)結(jié)構(gòu)——使用類似C 的string類的托管緩沖?;蛘?


對(duì)不安全的數(shù)據(jù)類型系統(tǒng)地使用安全的操作。通過把strcpy更換為有大小限制的字符串復(fù)制操作strncpy,就可以使上面的C代碼段得到保護(hù)。


char *safer_copy(const char *source)
{
char *buffer = new char[10];

strncpy(buffer, source, 10);

return buffer;
}

9 檢查所有的返回值

如果一個(gè)函數(shù)返回一個(gè)值,它這樣做肯定是有理由的。檢查這個(gè)返回值。如果返回值是一個(gè)錯(cuò)誤代碼,你就必須辨別這個(gè)代碼并處理所有的錯(cuò)誤。不要讓錯(cuò)誤悄無聲息地侵入你的程序;忍受錯(cuò)誤會(huì)導(dǎo)致不可預(yù)知的行為。


這既適用于用戶自定義的函數(shù),也適用于標(biāo)準(zhǔn)庫函數(shù)。你會(huì)發(fā)現(xiàn):大多數(shù)難以察覺的錯(cuò)誤都是因?yàn)槌绦騿T沒有檢查返回值而出現(xiàn)的。不要忘記,某些函數(shù)會(huì)通過不同的機(jī)制(例如,標(biāo)準(zhǔn)C庫的errno)返回錯(cuò)誤。不論何時(shí),都要在適當(dāng)?shù)募?jí)別上捕獲和處理相應(yīng)的異常。


10 審慎地處理內(nèi)存(和其他寶貴的資源)

對(duì)于在執(zhí)行期間所獲取的任何資源,必須徹底釋放。內(nèi)存是這類資源最常提到的一個(gè)例子,但并不是唯一的一個(gè)。文件和線程鎖也是我們必須小心使用的寶貴資源。做一個(gè)好的“管家”。


不要因?yàn)橛X得操作系統(tǒng)會(huì)在你的程序退出時(shí)清除程序,就不注意關(guān)閉文件或釋放內(nèi)存。對(duì)于你的代碼還會(huì)執(zhí)行多長(zhǎng)時(shí)間,是否會(huì)耗盡所有的文件句柄或占用所有的內(nèi)存,其實(shí)你一無所知。你甚至不能肯定操作系統(tǒng)是否會(huì)完全釋放你的資源,有的操作系統(tǒng)就不是這樣的。


有一個(gè)學(xué)派說:“在確定你的程序可以運(yùn)行之前,不要擔(dān)心內(nèi)存的釋放;只有在能夠確定之后再添加所有相關(guān)的釋放操作。”這種觀點(diǎn)大錯(cuò)特錯(cuò),是一種荒謬而且危險(xiǎn)的做法。它會(huì)使你在使用內(nèi)存時(shí)出現(xiàn)許許多多的錯(cuò)誤;你將不可避免地在某些地方忘記釋放內(nèi)存。


關(guān)鍵概念** 重視所有稀有的資源**。審慎地管理它們的獲取和釋放。


Java和.NET使用垃圾回收器來執(zhí)行這些繁重的清潔工作,所以你可以“忘記”釋放資源。讓它們進(jìn)入工作狀態(tài),這樣在運(yùn)行時(shí)將會(huì)不時(shí)地進(jìn)行清掃。這真是一種享受,不過,不要因此而對(duì)安全性抱有錯(cuò)誤的想法。


你仍然需要思考。你必須顯式地終止對(duì)那些不再需要,或不會(huì)被自動(dòng)清除的對(duì)象的引用;不要意外地保留對(duì)對(duì)象的引用。不太先進(jìn)的垃圾回收器也很容易會(huì)被循環(huán)引用蒙蔽(例如,A引用B,B又引用A,除此之外沒有對(duì)A和B的引用)。這會(huì)導(dǎo)致對(duì)象永遠(yuǎn)不會(huì)被清除;這是一種難以發(fā)現(xiàn)的內(nèi)存泄漏形式。


11 在聲明位置初始化所有變量

這是一個(gè)顯而易見的問題。如果你初始化了每個(gè)變量,它們的用途就會(huì)是明確的。依靠像“如果我不初始化它,我就不關(guān)心初始值”的經(jīng)驗(yàn)主義是不安全的。


代碼將會(huì)發(fā)展。未初始化的值以后可能隨時(shí)都會(huì)變成問題。


C和C 使這個(gè)問題更加復(fù)雜化。如果你意外地使用了一個(gè)沒有初始化的變量,那么你的程序在每次運(yùn)行的時(shí)候都將得到不同的結(jié)果,這取決于當(dāng)時(shí)內(nèi)存中的垃圾信息是什么。在一個(gè)地方聲明一個(gè)變量,隨后再對(duì)它進(jìn)行賦值,在這之后再使用它,這樣會(huì)為錯(cuò)誤打開一個(gè)窗口。


如果賦值的語句被跳過,你就會(huì)花費(fèi)大量的時(shí)間來尋找程序隨機(jī)出現(xiàn)各種行為的原因。在聲明每個(gè)變量的時(shí)候就對(duì)它進(jìn)行初始化,就可以把這個(gè)窗口關(guān)上,因?yàn)榧词钩跏蓟瘯r(shí)賦的值是錯(cuò)誤的,至少出現(xiàn)的錯(cuò)誤行為也是可以預(yù)知的。


比較安全的語言(如Java和C#)通過為所有變量定義初始值,回避了這個(gè)易犯的錯(cuò)誤。在聲明變量的時(shí)候?qū)λM(jìn)行初始化仍然是一種好的做法,這樣可以提高代碼的明確性。


12 盡可能推遲一些聲明變量

盡可能推遲一些聲明變量,可以使變量的聲明位置與使用它的位置盡量接近,從而防止它干擾代碼的其他部分。這樣做也使得使用變量的代碼更加清晰。你不再需要到處尋找變量的類型和初始化,在附近聲明使這些都變得非常明顯。


不要在多個(gè)地方重用同一個(gè)臨時(shí)變量,即使每次使用都是在邏輯上相互分離的區(qū)域中進(jìn)行的。變量重用會(huì)使以后對(duì)代碼重新完善的工作變得異常復(fù)雜。每次都創(chuàng)建一個(gè)新的變量——編譯器會(huì)解決任何有關(guān)效率的問題。


13 使用標(biāo)準(zhǔn)語言工具

在這方面,C和C 都是一場(chǎng)噩夢(mèng)。它們的規(guī)范有許多不同的版本,使得許多情況成為了其他實(shí)現(xiàn)的未定義行為?,F(xiàn)如今有很多種編譯器,每個(gè)編譯器都有一些與其他編譯器稍有不同的行為。這些編譯器大部分是相互兼容的,但是仍然存在大量的繩索會(huì)套住你的脖子。


明確地定義你正在使用的是哪個(gè)語言版本。除非你的項(xiàng)目要求你(最好是有一個(gè)好的理由),否則不要將命運(yùn)交給編譯器,或者對(duì)該語言的任何非標(biāo)準(zhǔn)的擴(kuò)展。如果該語言的某個(gè)領(lǐng)域還沒有定義,就不要依賴你所使用的特定編譯器的行為(例如,不要依賴你的C編譯器將char作為有符號(hào)的值對(duì)待,因?yàn)槠渌木幾g器并不是這樣的)。


這樣做會(huì)產(chǎn)生非常脆弱的代碼。當(dāng)你更新了編譯器之后,會(huì)發(fā)生什么?


一位新的程序員加入到開發(fā)團(tuán)隊(duì)中,如果他不理解那些擴(kuò)展,會(huì)發(fā)生什么?依賴于特定編譯器的個(gè)別行為,將導(dǎo)致以后難以發(fā)現(xiàn)的錯(cuò)誤。


14 使用好的診斷信息日志工具

當(dāng)你編寫新的代碼時(shí),常常會(huì)加入很多診斷信息,以確定程序的運(yùn)行情況。在調(diào)試結(jié)束后是否應(yīng)該刪除這些診斷信息呢?保留這些信息對(duì)以后再次訪問代碼會(huì)帶來很多方便,特別是如果在此期間可以有選擇地禁用這些信息。


有很多診斷信息日志系統(tǒng)可以幫助實(shí)現(xiàn)這種功能。這些系統(tǒng)中很多都可以使診斷信息在不需要的時(shí)候不帶來任何開銷;可以有選擇地使它們不參加編譯。


15 審慎地進(jìn)行強(qiáng)制轉(zhuǎn)換

大多數(shù)語言都允許你將數(shù)據(jù)從一種類型強(qiáng)制轉(zhuǎn)換(或轉(zhuǎn)換)為另一種類型。這種操作有時(shí)比其他操作更成功。如果試著將一個(gè)64位的整數(shù)轉(zhuǎn)換為較小的8位數(shù)據(jù)類型,那么其他的56位會(huì)怎么樣呢?你的執(zhí)行環(huán)境可能會(huì)突然拋出異常,或者悄悄地使你數(shù)據(jù)的完整性降級(jí)。很多程序員并不考慮這類事情,所以他們的程序就會(huì)表現(xiàn)出不正常的行為。


如果你真的想使用強(qiáng)制轉(zhuǎn)換,就必須對(duì)之深思熟慮。


你所告訴編譯器的是:“忘記類型檢查吧:我知道這個(gè)變量是什么,而你并不知道?!蹦阍陬愋拖到y(tǒng)中撕開了一個(gè)大洞,并直接穿越過去。這樣做很不可靠。


如果你犯了任何一種錯(cuò)誤,編譯器將只會(huì)靜靜地坐在那里小聲嘀咕道:“我告訴過你的。”如果你很幸運(yùn)(例如使用Java或C#),運(yùn)行時(shí)可能會(huì)拋出異常以讓你了解發(fā)生了錯(cuò)誤,但這完全依賴于你要進(jìn)行的是什么轉(zhuǎn)換。


C和C 對(duì)于數(shù)據(jù)類型的精度并不明確,所以對(duì)于數(shù)據(jù)類型的可互換性不要做任何假設(shè)。不要假設(shè)int和long的大小相同并且可以相互賦值,即使你在你的平臺(tái)上僥幸可以這樣做。代碼可以在平臺(tái)之間移植,但是糟糕的代碼可移植性很差。


16 細(xì)則

低級(jí)別防御性代碼的編寫技巧有很多。這些技巧是日常編程工作的組成部分,包含在對(duì)現(xiàn)實(shí)世界的一種健康的懷疑當(dāng)中。下面的幾條細(xì)則值得考慮:


提供默認(rèn)的行為 大多數(shù)語言都提供了一條switch語句;這些語言都將碰到default case的執(zhí)行情況。如果default case是錯(cuò)誤的,在代碼中將錯(cuò)誤情況明示出來。如果一切都正常,也要在代碼中明示順利執(zhí)行的情況,只有這樣維護(hù)代碼的程序員才會(huì)理解程序的執(zhí)行情況。


同樣地,如果你要編寫一條不帶else子句的if語句,停下來想一想,你是否應(yīng)該處理這個(gè)邏輯上的默認(rèn)情況。


遵從語言習(xí)慣

這條簡(jiǎn)單的建議將確保你的讀者可以明白你所編寫的所有代碼。他們做出的錯(cuò)誤設(shè)想會(huì)更少。


檢查數(shù)值的上下限

即使是最基本的計(jì)算,也會(huì)使數(shù)值型變量上溢或下溢。對(duì)此要非常注意。語言規(guī)范或核心庫提供了一些機(jī)制,用來確定各個(gè)標(biāo)準(zhǔn)類型的大小——?jiǎng)e忘了使用這些機(jī)制。確保你了解所有可用的數(shù)值類型,以及每種類型最適合的情況。


檢查并確保每一次運(yùn)算都是可靠穩(wěn)定的。例如,確保自己一定不要使用可能會(huì)造成除0錯(cuò)誤的值。


正確設(shè)置常量

C或C 語言的程序員真的應(yīng)該對(duì)常量的設(shè)置保持高度警惕,這會(huì)讓日子好過很多。盡可能將所有可以設(shè)置成常量的都設(shè)為常量。這樣做有兩個(gè)好處:首先,常量的限制條件可以充當(dāng)代碼記錄;其次,常量使編譯器可以找到你所犯下的愚蠢錯(cuò)誤。這樣,你就可以避免修改超出上下限的數(shù)據(jù)了。



原文鏈接:


http://www.uml.org.cn/codeNorms/201007165.asp


https://blog.csdn.net/everpenny/article/details/6316698




—— The End ——



本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉