新聞中心

EEPW首頁 > 牛人業(yè)話 > 寫代碼要小心地盤 陰溝里也能翻了船

寫代碼要小心地盤 陰溝里也能翻了船

作者:三昧道人 時間:2019-06-21 來源:電子產(chǎn)品世界 收藏

筆者的同事陽春君春節(jié)期間喝大了,樂極生悲摔傷了手。在做完手術(shù)后的復(fù)健階段,醫(yī)生讓他盤核桃,幫助恢復(fù)肌腱。

本文引用地址:http://m.butianyuan.cn/article/201906/401791.htm

可是,陽春君的手既肥且小,普通大小的核桃抓一個綽綽有余,抓兩個就頗有些力不從心。而且,“盤”核桃這活兒大有技術(shù)含量,揉、捏、捻、擼、搓,各種手法,各有各的門道。所以,這只平時敲鍵盤、寫的手剛開始“盤”核桃時,動作生硬,毫無章法。

玩家們盤上一段時間的核桃,就會變得既紅且圓潤。可核桃到了他的手里,過了一段時間,就好像受了十大酷刑一般,體無完膚,斑駁丑陋。讓人奇怪的是,雖然盤核桃接二連三地失敗,他的手竟而漸漸好了起來,又能噼里啪啦地敲了。

這段盤核桃的經(jīng)歷在陽春君的身上打下了深深的烙印。他經(jīng)常把我拉過去,幫著一起找運(yùn)行出錯的中的bug。看著他那縱橫交錯的代碼,我經(jīng)常提醒他把代碼再重構(gòu)一下,這樣方便找問題。每每這時,他就會盯著屏幕上的代碼,對著不知藏在何處的bug咬牙切齒地說:盤它!

timg (1).jpg

1

萬物皆可盤,核桃如是,代碼亦然。

核桃自不必待言,渾然天成的疙疙瘩瘩,自然而言的天然丑,一副迫切求“盤”的樣子,求仁得仁,不盤它盤誰?

u=3566979592,4253186926&fm=26&gp=0.jpg

代碼呢?基督說,在神面前,人生而不完美。人猿同祖同宗,不完美的程序“猿”寫出來的代碼自然也不會盡善盡美了,故而同樣存在被“盤”的需求。

在被盤的過程中,核桃被千般揉捏,萬般搓捻,終于洗盡鉛華,文藝氣息盡顯。代碼則被一次次地重構(gòu),抽筋換骨,改頭換面,最終臻于穩(wěn)定可靠、好看好用。

盤核桃的過程是美妙的。十全老人曾作詩表達(dá)對盤核桃的喜愛:掌上旋日月,時光欲倒流。周身氣血涌,何年是白頭。盤得如癡如醉,忘了歲月之憂。

盤代碼的過程卻是苦樂夾雜的。倘若小心翼翼,技術(shù)精湛,代碼溫順如牛,在自己的手下一步步變得完美、和諧,碼農(nóng)一樣可以樂而忘憂??扇绻中拇笠猓虮P功很爛,搞得代碼猶如脫韁之馬,攜bug之威只是發(fā)出那冷笑,碼農(nóng)就只能周身氣血涌,早日白了頭了。

有那么幾次,筆者就因?yàn)椴恍⌒?,代碼沒有好好地盤,在陰溝里翻了船。

2

這個世界上最遙遠(yuǎn)的距離,不是相隔千山萬里,而是你站在我的面前,我就是搞不懂你。

對于代碼,對于程序,我經(jīng)常生出這種“你為什么就是不懂我?!”的哀怨。

1.jpg

比如我曾經(jīng)寫過下面這句代碼:

Ev_ia=Can_bms.ial+(uint16_t)Can_bms.iah<<8;

背景很簡單,就是根據(jù)BMS(電池管理系統(tǒng))這個CAN節(jié)點(diǎn)發(fā)來的電流高字節(jié)(iah)、低字節(jié)(ial)計算出當(dāng)前電動汽車的電流大小。計算方法為:高字節(jié)左移8位,再和低字節(jié)相加。

看,計算多么簡單,簡直是把心都剖開了給你看。但是,歲月劍拔弩張,這世界并非你想的那樣。

調(diào)試過程中,錯誤在第一時間就跳了出來,因?yàn)槲野l(fā)現(xiàn),BMS送來的低字節(jié)電流為0x64,高字節(jié)電流為0時,運(yùn)算結(jié)果居然成了0x6400。

錯誤是顯然的,原因也是簡單的。我立馬敏銳地意識到是“運(yùn)算符的優(yōu)先級”問題。查表一看,果然如此。

左移運(yùn)算符(<<)的優(yōu)先級低于相加運(yùn)算符(+),故而,在計算機(jī)的世界中,真正的運(yùn)算過程為:

0x64+(uint16_t)0 = 0x64;0x64 << 8 = 0x6400

而不是自己心中的想當(dāng)然:0x64 + (0 << 8)=0x64。

細(xì)究起來,這可以被認(rèn)為是人-機(jī)之間存在誤會,而誤會無處不在。

宇宙黑暗森林中的各個文明之間充滿了猜疑,隨時準(zhǔn)備發(fā)起黑暗打擊。地球文明中的超級大國美國和中國之間充滿了猜忌,貿(mào)易戰(zhàn)打得如火如荼。就是朝朝暮暮的情侶之間也各種誤會,隨時捕捉著對方的不信任。

碼農(nóng)和他鐘愛的程序之間吶,也被這宿命般的誤會搞得不能你儂我儂,地久天長到那山無棱。

3

上面這個bug還算是有情可原,畢竟世間之事千般萬種,被世事搞得體力虛弱、腦力孱弱的碼農(nóng)們,很難在編程語言的語法上掌握地非常全面。

世道艱難,人生無常,程序猿過得很累,我們要原諒他。

但是還有一種本來不該出現(xiàn)的bug,它不僅出現(xiàn)了,竟然還長時間地呆在那里,直到你把它捉走時,才會發(fā)覺這種bug出現(xiàn)得多么不可理喻。

筆者就在一款產(chǎn)品的小批量試產(chǎn)階段發(fā)現(xiàn)了一個本不該出現(xiàn)、出現(xiàn)后也不該活過半天的bug。這只bug通過了功能確認(rèn),扛過了車廠的路試,活到了小批量試產(chǎn)階段。

這款產(chǎn)品中有個車速檢測功能,通過ABS發(fā)來的兩個字節(jié)的車速數(shù)據(jù)計算出當(dāng)前車速,根據(jù)車速的變化自動對車門上鎖。

兩個高低字節(jié)經(jīng)過移位、相加得到一個雙字節(jié)數(shù)據(jù),似曾相識吧。沒錯,和上面那個計算電動車當(dāng)前消耗電流的方法一樣。

吃一塹長一智的筆者肯定不會犯同樣的錯誤,這一次,灑家犯了新的錯誤。

2.jpg

我居然把存放一個中間車速的變量定義成了8位單字節(jié)類型!把一個本該是16位雙字節(jié)類型的數(shù)字塞到單字節(jié)里,你可以想象那是怎樣一種荒唐的bug。

uint16_t Speed_abs;

//Uint8_t Speed_abs;//錯誤就在這里?。?!

Speed_abs=can_ABS330.msg_data.sig.vehicle_speed_l+ (can_ABS330.msg_data.sig.vehicle_speed_h << 8);

if(Speed_abs <= 0x12c0){

Speed_quant = Speed_abs;

CheckSpeed();

}

出現(xiàn)這種錯誤,當(dāng)然是不可原諒的,但是,人有失算,馬有失蹄,偶爾腦袋短路,似乎也無法全然避免。事情的詭異當(dāng)然不在這里,它的神奇之處在于,這種低級別的bug居然一路通關(guān),活到了最后。

事后想來,整件事都透露著神奇和詭異。

人生充滿了陰差陽錯,各種說不清道不明的東西,會讓我們陷入莫名其妙的境地。這個神奇的bug活了這么久,將這種陰差陽錯詮釋地淋漓盡致。

4

這段錯誤的代碼是在產(chǎn)品開發(fā)的最后階段引入的。最后階段的主要工作是查缺補(bǔ)漏,盡可能地堵住各種可能的隱患。

本來的車速計算和判斷程序里沒有和最高有效值0x12c0的判斷,直接從ABS數(shù)據(jù)計算出當(dāng)前車速,賦值給Speed_quant。不知怎么的,我覺得最好是在這里加上對最高有效值的判斷,于是就定義了一個中間變量Speed_abs,當(dāng)它小于等于0x12c0時,再把它賦值給Speed_quant。

沒用的好心,結(jié)果卻變成了壞事。本來取值區(qū)間在0-0x12c0之間的車速值,被硬生生地限制在了單字節(jié)的取值區(qū)間(0-0xff)里。想一下吧,有一個神力把三維的你給拍扁了,放進(jìn)了二維的畫里面,憋屈不憋屈?

本來,這樣的bug不該活過半分鐘,結(jié)果,因?yàn)槲覀冞@個產(chǎn)品是在車廠的試驗(yàn)車上進(jìn)行驗(yàn)證,試驗(yàn)車的油箱基本上空了,車廠工作人員也不允許我們開起車來跑,于是,這個判斷車速、賦值車速、根據(jù)車速自動閉鎖的程序分支一直沒有得到驗(yàn)證。Bug就這樣活過了第一關(guān)。

盡管如此,在路試階段,由于這個bug的存在,加速閉鎖功能就失效了。那么,跑車的路試員怎么竟而沒有發(fā)現(xiàn)這么明顯的錯誤呢?

難道路試員每次開車之前,都會先中控閉鎖一下?或者我們的合作伙伴給車廠送的樣件里燒錄的居然不是我給他們的最后一版程序?

實(shí)情如何,已無歷史可考了,這樁事件終于成了令我百思不得其解的懸案。只有它的詭異,時常浮現(xiàn)在我的心頭,讓我在敲代碼時更存了一分小心翼翼和戰(zhàn)戰(zhàn)兢兢。

戰(zhàn)戰(zhàn)兢兢,如履薄冰,如此,君子可不立于危地。

5

對于一個原始狀態(tài)的代碼,一位好的碼農(nóng)會耐心地在之上精耕細(xì)作,仔細(xì)地捉蟲,耐心地施肥,小心地呵護(hù),務(wù)求盡善盡美,這樣子,才能搞出健壯、耐看的果實(shí)來,這樣子盤出來的代碼才能經(jīng)受住時間的考驗(yàn)。

相反,有的碼農(nóng)寫了一段代碼后就把它扔在那里,就好像只管生不管養(yǎng)的無良父母一樣,急火火地又去寫下一段代碼。沒有對代碼的耐心呵護(hù),缺乏對它的修剪、完善,最終,搞出的程序總是既不穩(wěn)定,又不耐看。

u=3790028067,1002618127&fm=26&gp=0.jpg

不愿意耐心找bug改代碼的人,實(shí)際上犯的是貪功冒進(jìn)的錯誤,總以為量變才能質(zhì)變,多寫代碼才能把水平提升上去。其實(shí)這種認(rèn)識非常片面,這種方式也很不可取,對自我能力的提升非常不利。

因?yàn)?,只有在一次次的量變中有小的質(zhì)變,才能最終練成編碼神功。每次都馬馬虎虎,這樣的編碼經(jīng)歷就像掰玉米的狗熊一樣,一邊得到,一邊丟棄,到最后其實(shí)剩不下多少有用的東西。

不愿意下功夫盤代碼,也是一種懶惰。好逸惡勞是人之通病,所以好的程序猿總是難尋。

對待代碼,需要確立不求盡善盡美、但求問心無愧的心態(tài)。要仔細(xì)地盤,耐心地盤。

想必,我的經(jīng)歷也能給大家一些啟發(fā):代碼一定要耐心地盤,陰溝里也能翻了船!



關(guān)鍵詞: 汽車電子 代碼

評論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉