一行代碼引發(fā)慘案,這似乎有點兒夸張,但看完文章后你可能就會改變看法。
災(zāi)難降臨
時間回到1991年2月25號,在一個月黑風(fēng)高的夜晚,一枚飛毛腿導(dǎo)彈,悄無聲息地飛臨沙特的達(dá)蘭美軍軍營上空,而已經(jīng)連續(xù)作戰(zhàn)4天的美軍愛國者導(dǎo)彈防御系統(tǒng),沒能識別出這一危險的目標(biāo)。這個大殺器直撲美軍營地,造成了28名士兵死亡,100多人受傷,可謂慘烈!要知道整個海灣戰(zhàn)爭美軍一共才戰(zhàn)死了148人啊。
墨菲定律
在戰(zhàn)爭中大放異彩,被吹噓的神乎其神的愛國者防御系統(tǒng),是如何犯下這個致命的錯誤的呢?這個起因倒是不復(fù)雜,其實在2月11號,以色列軍方就已經(jīng)發(fā)現(xiàn),系統(tǒng)存在隱患。他們發(fā)現(xiàn)在愛國者系統(tǒng)連續(xù)工作8小時后,目標(biāo)捕獲精度會下降20%,在連續(xù)工作20小時以后,系統(tǒng)看起來似乎失效了。
在接到這一上報后,美國軍方大意了,他們覺得反導(dǎo)系統(tǒng)不會連續(xù)工作這么長時間,雖然開始給軟件打補丁,但由于是在戰(zhàn)時狀態(tài),進(jìn)度比較慢,于是軍方發(fā)出命令,讓系統(tǒng)不要工作太長時間。但是這個太長時間是多久?并沒有說個明白。于是墨菲定律又起作用了:如果事情有變壞的可能,不管這種可能性有多小,它總會發(fā)生。于是就發(fā)生了文章開頭的一幕。那么問題出在哪兒了呢?
水落石出
隨后的調(diào)查顯示,問題的根源,在軟件中一個隱藏很深的Bug。愛國者系統(tǒng)軟件,使用了一個3字節(jié),也就是24bit的變量存儲一個0.1秒的單位時間,存儲時間值和真實時間之間,有一個微小的差值,這個時間差值在系統(tǒng)運行時逐漸累積,在系統(tǒng)不間斷長時間運行后,積累的時間差值過大,最終導(dǎo)致了嚴(yán)重問題。
原來不像我們平常計算使用10進(jìn)制,計算機系統(tǒng)用2進(jìn)制存儲數(shù)據(jù),0.1秒變成2進(jìn)制是0.0001100110011001100110011001100....,這是一個無限循環(huán)小數(shù),當(dāng)用24bit 的變量存儲它時,精度只保留到前24bit,后面的都被舍棄掉了,那這個誤差有多少呢?換算成10進(jìn)制是0.000000095秒,這看起來是一個很微不足道的誤差,但是工作100小時后,這個誤差會積累到0.000000095×100(小時)×60(分鐘)×60(秒)×10(次/秒)=0.34秒。這似乎仍然是一個非常非常短的時間,然而,這足以讓以1676米/秒高速飛行的飛毛腿導(dǎo)彈,飛過569.84米,輕松突破本以為堅不可摧的防線了。
給我們的警示
我們在編寫代碼時,一定要注意每一個變量的位數(shù),而且需要注意的是,在不同的操作系統(tǒng),或者使用不同的編譯器時,同一個類型的變量長度可能都是不同的。這在移植代碼時尤其要注意,原來工作正常的代碼,換個平臺,換個編譯器可能就不同了。
需要注意計算過程有沒有造成結(jié)果精度的下降,有沒有產(chǎn)生累積誤差。計算過程有沒有可能造成結(jié)果溢出,即結(jié)果小于0,或大于變量所允許最大值的可能。
整型,無符號型,浮點型等變量類型,不要混用,否則強制類型轉(zhuǎn)換可能導(dǎo)致不可預(yù)知的結(jié)果。
掃碼加入嵌入式交流群: