編程規范哪家強 Misra C姊妹篇再上場(chǎng)
據說(shuō),在中國的演藝界,有兩個(gè)圈最講究規矩了。
一個(gè)是小品圈,以東北王為代表,一個(gè)頭磕到地上,便入了趙家門(mén),得守趙氏家法。
還有一個(gè)便是相聲界,長(cháng)幼尊卑更是秩序森嚴,跟師父鬧掰便是叛出師門(mén),在相聲界基本上便沒(méi)有了立足之地。
還有便是軍隊,更是紀律嚴明,講究個(gè)戰前且莫議論紛紛,開(kāi)戰便要萬(wàn)眾一心。因為,主帥有令,將士效命,才能攻無(wú)不克,戰無(wú)不勝。您不信?君不見(jiàn),楊主簿啃著(zhù)雞肋上斷頭臺否?
編程這種“小事”,同樣也得守規矩!
1、編程規范的重要性
之前,灑家寫(xiě)過(guò)一篇《編程規范哪家強 我把Misra C講一講》,大致講了Misra C誕生的背景及其規則背后的原因。今天,灑家不惜筆墨,苦口婆心,跟大家談一談編程規范的重要性。
孔老夫子總結自己一生時(shí)曾曰:“吾十有五而志于學(xué),三十而立,四十而不惑,五十而知天命,六十而耳順,七十而從心所欲,不逾矩。”
西方人秉承Follow your heart,搞得毒品泛濫,小姐滿(mǎn)大街??桌戏蜃訁s能做到“從心所欲,不逾矩”,為什么?
因為,當持戒成為一種習慣,不逾矩便成了從心所欲的自然。持守戒律、遵守規矩非但不會(huì )處處束縛你,反而讓你在道德準則、社會(huì )秩序允許的范圍內得到了最大程度的自由。那些淺薄的西方人,是把這個(gè)邏輯搞反了呀!
風(fēng)箏是自由的,是因為有根線(xiàn),讓它既能翱翔于九天,又能隨時(shí)隨刻被拉牽?;疖?chē)是自由的,是因為有一雙鐵軌,讓它既能風(fēng)馳電掣越千山,又能平平穩穩進(jìn)車(chē)站。代碼是自由的,是因為有規范,讓它既能把您的所思所想付諸實(shí)踐,又能避免翻車(chē),給你瞎搗亂。
對于寫(xiě)代碼來(lái)說(shuō),編程規范不會(huì )限制自由,它只會(huì )限制滋生的混亂。
一個(gè)不遵循規范的代碼不僅僅虱子多了真犯愁,bug多了直撓頭,還會(huì )在閱讀、修改、維護上會(huì )遇到理解上的障礙。
對于剛上手不久的菜鳥(niǎo)級碼農來(lái)說(shuō),遵循規范意味著(zhù)嚴格的自律、小心翼翼和偏執,但這能減少bug和隱患。而且,一旦養成了習慣,習慣就變成了自然,這時(shí)候,不符合規則的代碼一入你的法眼,你就不由自主地要把它改掉,讓這些不規矩的代碼快滾蛋。
對一個(gè)組織而言,遵守統一的編程規范意味著(zhù)書(shū)同文、車(chē)同軌,就像月老的紅絲線(xiàn),把大家伙的心兒緊相連,從而大幅提高協(xié)作效率,真正做到團隊作戰。
2、面向可靠性/安全的設計規范
這世上有一個(gè)神奇的二八定律,比方說(shuō)20%的人掌握著(zhù)世界上80%的財富,20%的人干著(zhù)80%的活。。。
干過(guò)大批量量產(chǎn)電子產(chǎn)品的攻城獅們還發(fā)現,20%的時(shí)間能干成80%的活,接下來(lái)要用80%的時(shí)間,把剩下20%的細節好好打磨。
之所以如此,是因為這些產(chǎn)品在上市前需要經(jīng)過(guò)研發(fā)團隊非常嚴苛的反復測試。為什么要反復測試?不要問(wèn),問(wèn)就是不懂!難不成,出了問(wèn)題,你能牛得像特斯拉那樣非但拒絕認錯,還要教育教育用戶(hù)?
那么,“嚴苛”在哪里?“反復測試”些什么呢?除了正常邏輯、常規條件,還需要反復測試Corner case(邊界條件/邊角案例)!
佛說(shuō),萬(wàn)事萬(wàn)物,因緣和合而生,因緣別離而滅。大部分條件下,因緣和合,產(chǎn)品穩定運行,但一旦超過(guò)了某個(gè)臨界點(diǎn),滿(mǎn)足了邊界條件,如果處理失當,就可能因緣別離,功能失常了。
何謂邊界條件?其定義并不統一,從實(shí)際應用來(lái)講,一般是指很少發(fā)生的情景、參數異常、噪聲或者極端情況。開(kāi)發(fā)產(chǎn)品需要充分考慮邊界條件,或施加約束,針對處理,或圍住撈凈,避免漏網(wǎng),它會(huì )直接關(guān)乎到產(chǎn)品的可靠性和功能安全。
但是,產(chǎn)品的可靠性是設計出來(lái)的,而非靠測試測出來(lái)。在最初的設計階段就納入功能安全的理念,才能強本固基,扎下可靠性的底盤(pán)。
對于內嵌C代碼的電子產(chǎn)品而言,可靠性/功能安全和代碼的靈活性卻往往是一體兩面,王不見(jiàn)王,二龍不相見(jiàn)。C語(yǔ)言的靈活性,可以助力高手鬼斧神工,天外飛仙,也能讓菜鳥(niǎo)處處挖坑,埋下風(fēng)險。
凡事皆是破壞容易建設難,在靈活的語(yǔ)言特性下,要把程序寫(xiě)糟很容易,想寫(xiě)好卻很難。如果沒(méi)有一個(gè)嚴格、安全的設計規范來(lái)把關(guān),很容易把代碼寫(xiě)爛。
Misra C,正是為了對治C語(yǔ)言的靈活性、提高代碼的可靠性橫空出世的尚方寶劍。
Misra C的規則,大多來(lái)自一線(xiàn)工程師/專(zhuān)家多年的編程實(shí)踐,提煉于多年軟件設計的教訓和經(jīng)驗。一時(shí)理解不了,也是正常表現,您只需多多編程實(shí)戰,切不可自以為是,兩眼朝天。
畢竟,法律條文都會(huì )看,但只有羅老師的粉絲過(guò)千萬(wàn)!
3、MISRA-C 規則分類(lèi)及舉例
務(wù)虛務(wù)實(shí),相得益彰,上點(diǎn)干貨,才見(jiàn)真章。下面跟大家分享,Misra C針對C語(yǔ)言的籬笆下的一些樁。
3.1 被誤解的語(yǔ)言特性
3.1.1 char只用作字符
畢達哥拉斯學(xué)派有一句名言:萬(wàn)物皆數。生于俄羅斯的我國大詩(shī)仙李白對此深有體會(huì ),因為他曾喃喃自語(yǔ):白發(fā)三千丈,緣愁似個(gè)長(cháng)?也曾大聲驚呼:飛流直下三千尺,疑是銀河落九天。
詩(shī)仙何以不識數?因為,在他的慧眼里,數不是數,是帶著(zhù)詩(shī)情畫(huà)意的字符。在計算機的世界里,也有這樣一個(gè)獨特的數據類(lèi)型char,你也不要把它當成數,而要當成字符。
首先,這意味著(zhù)它的取值區間是[-128,127],其次,char型應該只用做“字符”,不要當成“數字”來(lái)用??纯聪旅孢@個(gè)例子:
char i;
i = 131;
if(i > 130){
Fun();
}
會(huì )如你所愿地執行Fun()嗎?當然,不會(huì )!
所以,Misra C規則5.1規定,“單純的char類(lèi)型只能用于存儲和使用字符值”。
3.1.2自動(dòng)變量不會(huì )自動(dòng)初始化
先上個(gè)例子:
uint8_t Fun(void)
{
uint8_t i;
...
if(0 == i){
Fun2();
}
}
同樣,不會(huì )執行Fun2()。
很多人會(huì )自以為是地想,科技在發(fā)展,時(shí)代在進(jìn)步,現在的開(kāi)發(fā)環(huán)境這么友好,它肯定會(huì )把變量i自動(dòng)賦值為0的吧?
答案是No! 在C語(yǔ)言里,只有全局變量和靜態(tài)局部變量會(huì )默認賦值為0,非靜態(tài)的局部變量隨機賦值,所以,Misra C規則9.1規定:所有自動(dòng)變量在使用前都應該被賦值!
3.2 增強程序的清晰
3.2.1 定義清晰的數據類(lèi)型
應該使用指示了大小和符號的typedef 以代替基本數據類(lèi)型,灑家在16位單片機上定義的常用類(lèi)型如下:
typedef signed char sint8_t;
typedef unsigned char uint8_t;
typedef signed int sint16_t;
typedef unsigned int uint16_t;
typedef float float32_t;
typedef unsigned long uint32_t;
3.2.2 不要使用逗號運算符
比如下面這段代碼占了5行:
if(TRUE == Val){
motor->pointer = 0;
motor->pointer_old = 0;
motor->cmd_dir = CLKWISE;
}
有的偏執狂為了精簡(jiǎn)行數,改成下面這樣的兩行:
if(TRUE == Val)
motor->pointer = 0, motor->pointer_old = 0, motor->cmd_dir = CLKWISE;
好多人get不到這種方式的缺點(diǎn)。想想一個(gè)場(chǎng)景,如果這是你從別人手中接手的代碼,看著(zhù)怪不怪?是不是懷疑哪個(gè)逗號搞錯了,應該改成分號來(lái)著(zhù)?
這背后,是律己從寬、料敵從嚴的人性??!
3.3杜絕奇技淫巧-笨拙則魯棒
對工程師來(lái)說(shuō),天才的設計是真正的浪漫。在自己得意的作品中留下一些小心思,是碼農們對庸常生活的一種反抗。
于是,各種花哨的小動(dòng)作就出現在了本該嚴謹的編碼實(shí)踐中。舉個(gè)例子:
uint8_t *** ptr;
指向xx的指針的指針的指針,多燒腦,多“美妙”。
可是,君子藏器于身,以鈍示人,以鋒策己。搞得這么花里胡哨,真以為過(guò)了一段時(shí)間自己能記牢?
3.4 不要依賴(lài)編譯器
不要過(guò)分依賴(lài)C表達式中的運算符優(yōu)先規則
比如下面這個(gè)程序:
uint8_t ial,iah;
uint16_t ia;
ia = ial + iah << 8;
初衷很簡(jiǎn)單,將兩個(gè)八位數據連接成一個(gè)16位數據。上面的錯誤在哪里?‘+’的優(yōu)先級大于‘<<’,所以應該改成下面這種形式:
ia = ial + (iah << 8);
不知不覺(jué),文章就變得又臭又長(cháng)了。收工!
文:三少爺
*博客內容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀(guān)點(diǎn),如有侵權請聯(lián)系工作人員刪除。
超聲波液位計相關(guān)文章:超聲波液位計原理
液位計相關(guān)文章:磁翻板液位計原理