新聞中心

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

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

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

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

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

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

玩家們盤上一段時(shí)間的核桃,就會(huì)變得既紅且圓潤(rùn)??珊颂业搅怂氖掷铮^了一段時(shí)間,就好像受了十大酷刑一般,體無完膚,斑駁丑陋。讓人奇怪的是,雖然盤核桃接二連三地失敗,他的手竟而漸漸好了起來,又能噼里啪啦地敲了。

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

timg (1).jpg

1

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

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

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

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

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

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

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

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

2

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

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

1.jpg

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

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

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

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

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

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

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

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

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

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

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

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

3

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

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

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

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

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

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

吃一塹長(zhǎng)一智的筆者肯定不會(huì)犯同樣的錯(cuò)誤,這一次,灑家犯了新的錯(cuò)誤。

2.jpg

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

uint16_t Speed_abs;

//Uint8_t Speed_abs;//錯(cuò)誤就在這里!?。?/span>

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

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

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

4

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

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

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

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

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

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

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

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

5

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

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

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

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

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

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

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

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



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

評(píng)論


相關(guān)推薦

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

關(guān)閉