一、前言
我們?cè)趯W(xué)校學(xué)習(xí)或者有參加過(guò)C語(yǔ)言培訓(xùn)的話(huà),應(yīng)該都聽(tīng)說(shuō)過(guò)“不建議使用goto
語(yǔ)句”。但是,一般不會(huì)有人告訴你為什么不建議使用goto
語(yǔ)句,類(lèi)似于這種存在但不建議使用的關(guān)鍵詞還有很多。
今天,我們就一起來(lái)看看,那些在C語(yǔ)言中存在但又不建議使用的關(guān)鍵詞!
二、慎用goto關(guān)鍵詞
關(guān)于goto
語(yǔ)句的爭(zhēng)議已經(jīng)不是一天兩天了,大部分C語(yǔ)言老師在講到goto
這關(guān)鍵字的時(shí)候一般都會(huì)叫大家慎用goto
關(guān)鍵字。既然goto
語(yǔ)句C語(yǔ)言標(biāo)準(zhǔn)中定義了,那為什么不建議使用呢?
因?yàn)?code style="font-size:14px;padding:2px 4px;margin:0 2px;background-color:rgba(27,31,35,.05);font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;color:rgb(239,112,96);">goto語(yǔ)句不僅讓代碼的可讀性很差,隨意的跳出還會(huì)給程序帶來(lái)安全隱患。但正是這種幾乎被各大公司明令禁止使用的語(yǔ)句,在Linux內(nèi)核中卻被大量使用著。
這只能說(shuō)明一點(diǎn),那就是因?yàn)槲覀兯教肆耍?a target="_blank">公司怕因?yàn)槟愕囊痪?/span>goto
造成代碼莫名跑飛!
?
早期的程序員用goto
來(lái)解決代碼無(wú)法預(yù)料的后果,遇到什么問(wèn)題就用一句goto
,讓程序跳轉(zhuǎn)到某個(gè)指定語(yǔ)句。
但是如果你的水平不夠,不能完全理解整個(gè)代碼的執(zhí)行過(guò)程的話(huà),貿(mào)然使用goto
就可以出現(xiàn)莫名的問(wèn)題,并且程序還很難被查到!
不建議使用goto
語(yǔ)句的原因還有以下幾點(diǎn)原因:
-
goto
語(yǔ)句可以被結(jié)構(gòu)化程序的別的語(yǔ)句代替; -
goto
語(yǔ)句會(huì)導(dǎo)致程序可讀性下降,因?yàn)樵趯?shí)際程序中,goto
可以跳到任何地方,可以往前可以往后,看程序慢慢看,看到goto
然后又要去找標(biāo)識(shí)符到底跳到了哪里,可讀性嚴(yán)重下降,讓讀程序的人很不舒服; -
調(diào)試不舒服,調(diào)試程序時(shí),由于有
goto
亂跳的,這就很難調(diào)試,去掉嘛,要重新寫(xiě)代碼,不去掉,無(wú)從下手;
存在即合理,goto
語(yǔ)句也不例外,goto
它存在,確實(shí)在某些程序中使用可能有好處,但在我們學(xué)習(xí)的階段,應(yīng)該盡量不要碰這類(lèi)程序,養(yǎng)成一個(gè)好的編程習(xí)慣。記住一句話(huà):**別人寫(xiě)的goto我能看懂,但是我自己不會(huì)去寫(xiě)goto!
**
三、慎用extern關(guān)鍵詞
在C語(yǔ)言程序中,我們用extern
關(guān)鍵字對(duì)某個(gè)變量作 “外部變量申明” ,表示該變量是一個(gè)已經(jīng)定義的外部變量,編譯器就會(huì)自動(dòng)地在所有源文件里面查找該變量的定義。
但是在公司編程規(guī)范中有明確要求:不允許在C文件中使用 “extern” 來(lái)申明外部函數(shù)或全局變量
具體原因如下(其中一點(diǎn)原因):
這樣使用extern
來(lái)定義全局變量確實(shí)能給我們帶來(lái)了很大的便利,從而節(jié)省了我們很多的時(shí)間和精力。但是這樣做也會(huì)存在一些危險(xiǎn),比如我們?cè)?code style="font-size:14px;padding:2px 4px;margin:0 2px;background-color:rgba(27,31,35,.05);font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;color:rgb(239,112,96);">c3.c文件引用的在a1.c
文件的funca
函數(shù)原型由UINT funca(UINT uiValue)
變?yōu)?code style="font-size:14px;padding:2px 4px;margin:0 2px;background-color:rgba(27,31,35,.05);font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;color:rgb(239,112,96);">UINT funca (UINT uiValue1, UINT uiValue2)我們?cè)诰幾g的時(shí)候不會(huì)報(bào)錯(cuò),但是在我們執(zhí)行程序的時(shí)候會(huì)在使用該函數(shù)的時(shí)候存在危險(xiǎn),尤其是該函數(shù)若有一個(gè)參數(shù)為指針,極有可能會(huì)存在對(duì)指針的誤操作,而引起異常。
嵌入式特別是單片機(jī)的程序,最易犯的錯(cuò)誤是全局變量滿(mǎn)天飛。此現(xiàn)象在早期匯編轉(zhuǎn)型過(guò)來(lái)的程序員以及初學(xué)者中常見(jiàn),這幫家伙幾乎把全局變量當(dāng)作函數(shù)形參來(lái)用。
每當(dāng)看到這種程序,我總要戚眉變臉而后拍桌怒喝。沒(méi)錯(cuò),就是怒喝,我不否認(rèn)全局變量的重要性,但我認(rèn)為要十分謹(jǐn)慎地使用它,濫用全局變量會(huì)引申帶來(lái)其它更為嚴(yán)重的結(jié)構(gòu)性系統(tǒng)問(wèn)題。
-
濫用全局變量會(huì)造成不必要的常量頻繁使用,特別當(dāng)這個(gè)常量沒(méi)有用宏定義“正名”時(shí),代碼閱讀起來(lái)將萬(wàn)分吃力。
-
會(huì)導(dǎo)致軟件分層的不合理,全局變量相當(dāng)于一條快捷通道,它容易使程序員模糊了“設(shè)備層”和“應(yīng)用層”之間的邊界。寫(xiě)出來(lái)的底層程序容易自作多情地關(guān)注起上層的應(yīng)用。這在軟件系統(tǒng)的構(gòu)建初期的確效率很高,功能調(diào)試進(jìn)度一日千里,但到了后期往往bug一堆,處處“補(bǔ)丁”,雷區(qū)遍布。說(shuō)是度日如年舉步維艱也不為過(guò)。
-
由于軟件的分層不合理,到了后期維護(hù),哪怕僅是增加修改刪除小功能,往往要從上到下掘地三尺地修改,涉及大多數(shù)模塊,而原有的代碼注釋卻忘了更新修改,這個(gè)時(shí)候,交給后來(lái)維護(hù)者的系統(tǒng)會(huì)越來(lái)越像一個(gè)“泥潭”,注釋的唯一作用只是使泥潭上方再加一些烏煙瘴氣。
-
全局變量大量使用,少不了有些變量流連忘返于中斷與主回圈程序之間。這個(gè)時(shí)候如果處理不當(dāng),系統(tǒng)的bug就是隨機(jī)出現(xiàn)的,無(wú)規(guī)律的,這時(shí)候初步顯示出病入膏肓的特征來(lái)了,沒(méi)有大牛來(lái)力挽狂瀾,注定慢性死亡。
無(wú)需多言,您已經(jīng)成功得到一個(gè)畸形的系統(tǒng),它處于一個(gè)神秘的穩(wěn)定狀態(tài)!你看著這臺(tái)機(jī)器,機(jī)器也看著你,相對(duì)無(wú)言,心中發(fā)毛。你不確定它什么時(shí)候會(huì)崩潰,也不曉得下一次投訴什么時(shí)候道理。
然后,我告訴大家現(xiàn)實(shí)層面的后果是什么。
-
“老人”氣昂昂,因?yàn)橄到y(tǒng)離不開(kāi)他,所有“雷區(qū)”只有他了然于心。當(dāng)出現(xiàn)緊急的bug時(shí),只有他能夠搞定。你不但不能辭退他,還要給他加薪。
-
新人見(jiàn)光死,但凡招聘來(lái)維護(hù)這個(gè)系統(tǒng)的,除了改出更多的bug外,基本上一個(gè)月內(nèi)就走人,到了外面還宣揚(yáng)這個(gè)公司的軟件質(zhì)量有夠差夠爛。
-
隨著產(chǎn)品的后續(xù)升級(jí),幾個(gè)月沒(méi)有接觸這個(gè)系統(tǒng)的原創(chuàng)者會(huì)發(fā)現(xiàn),很多雷區(qū)他本人也忘記了,于是每次的產(chǎn)品升級(jí)維護(hù)周期越來(lái)越長(zhǎng),因?yàn)樾薷囊粋€(gè)功能會(huì)冒出很多bug,而按下一個(gè)bug,會(huì)彈出其他更多的bug。在這期間,又會(huì)產(chǎn)生更多的全局變量。終于有一天他告訴老板,不行啦不行啦,資源不夠了,ram或者flash空間太小了,升級(jí)升級(jí)。
-
客戶(hù)投訴不斷,售后也快崩潰了,業(yè)務(wù)員也不敢推薦此產(chǎn)品了,市場(chǎng)份額越來(lái)越小,公司形象越來(lái)越糟糕。
注:以上關(guān)于extern的建議來(lái)源于黃工的分享。
四、慎用指針
指針對(duì)于初學(xué)者來(lái)說(shuō)本來(lái)就是一個(gè)不易理解的東西,初學(xué)者一般都不能夠真正的理解指針,并且正確的使用指針,下面是初學(xué)者常犯的錯(cuò)誤:
空指針: 指針值為NULL的指針叫空指針,不能運(yùn)行解引用,一旦解引用空指針就會(huì)產(chǎn)生段錯(cuò)誤。
NULL在大多數(shù)系統(tǒng)的值為0,該地址儲(chǔ)存操作系統(tǒng)重啟的數(shù)據(jù)。
NULL也被當(dāng)作錯(cuò)誤標(biāo)志,如果函數(shù)的返回值是指針類(lèi)型,當(dāng)它的值是NULL時(shí)說(shuō)明執(zhí)行出現(xiàn)錯(cuò)誤。
如何避免空指針產(chǎn)生的段錯(cuò)誤:對(duì)來(lái)歷不明的指針進(jìn)行解引用前要先判斷是否為空
野指針: 指針變量的值是不確定的,隨機(jī)的,未知的,這種指針被稱(chēng)為野指針。
對(duì)野指針進(jìn)行解引用的后果:一切正常 (運(yùn)氣好)、段錯(cuò)誤 (大概率)、臟數(shù)據(jù) (堆內(nèi)存申請(qǐng)的越多,臟數(shù)據(jù)可能性越大)。
終結(jié)出來(lái)還是那句話(huà):**別人寫(xiě)的goto我能看懂,但是我自己不會(huì)去寫(xiě)goto!
**
五、編程規(guī)范
我在這里給大家分享一寫(xiě)我們公司的編程規(guī)范,大家可以學(xué)習(xí)一下!
- 不允許在C文件中使用“extern”來(lái)申明外部函數(shù)或全局變量;
- 禁止使用八進(jìn)制數(shù);
- bit位變量移植性差,應(yīng)避免使用。推薦使用boolean類(lèi)型;
- bit fields位域變量移植性差,不應(yīng)使用;
- uint, sint使用機(jī)器字長(zhǎng),雖然速度快,但有溢出風(fēng)險(xiǎn),應(yīng)避免使用;
- 指針的數(shù)學(xué)運(yùn)算只能用在指向數(shù)組或數(shù)組元素的指針上;
- 指針減法只能用在指向同一數(shù)組中元素的指針上;
- 數(shù)組的索引應(yīng)當(dāng)是指針數(shù)學(xué)運(yùn)算的唯一可允許的方式;
- 不應(yīng)在指針類(lèi)型和整型之間進(jìn)行強(qiáng)制轉(zhuǎn)換;
- 不應(yīng)在某類(lèi)型對(duì)象指針和其他不同類(lèi)型對(duì)象指針之間進(jìn)行強(qiáng)制轉(zhuǎn)換;
- 如果指針?biāo)赶虻念?lèi)型帶有const 或volatile 限定符,那么移除限定符的強(qiáng)制轉(zhuǎn)換是不允許的;
- 數(shù)學(xué)運(yùn)算時(shí),應(yīng)有效防止數(shù)據(jù)溢出;
六、結(jié)語(yǔ)
關(guān)于編程規(guī)范的問(wèn)題其實(shí)還有很多需要注意的事情,如果大家感興趣的話(huà),可以搜索一下網(wǎng)上總結(jié)好的編程規(guī)范范文,尤其是初學(xué)者,在最開(kāi)始就要養(yǎng)成一個(gè)良好的編程習(xí)慣,不理解的東西就盡量不要使用!
好了,以上就是今天分享的所有內(nèi)容,如有錯(cuò)誤,歡迎指正。
最后,愿讀到這篇文章的程序員們寫(xiě)的代碼永無(wú)bug!
??
評(píng)論
查看更多