嵌入式開發(fā)人員經(jīng)常抱怨沒有一種編程語言適合他們的特殊需求。在某種程度上,這種情況并不令人驚訝,因為盡管許多開發(fā)人員都在開發(fā)嵌入式應用程序,但他們?nèi)匀恢皇鞘澜缇幊躺鐓^(qū)的一小部分。盡管如此,有些語言的開發(fā)還是考慮到了嵌入式。值得注意的例子是PL/M、Forth和Ada,它們都被廣泛使用,但從未被普遍接受。其他語言,如Rust,正在獲得支持,但尚未成為主流。幾乎被普遍采用的折衷方案是C,如何使折衷方案最有效地發(fā)揮作用?
C語言結構緊湊,表達能力強,功能強大。它為程序員提供了編寫高效、可讀和可維護代碼的方法。所有這些特性都是它受歡迎的原因。不幸的是,這種語言還使粗心大意的開發(fā)人員編寫危險的、不安全的代碼,這些代碼在開發(fā)項目的所有階段和部署中都可能導致嚴重的問題。對于安全性和/或安全性是主要優(yōu)先事項的應用程序,語言的這些缺點是一個主要問題。
正是在這種背景下,在20世紀90年代末,汽車工業(yè)軟件可靠性協(xié)會(MISRA)推出了一套關于在車輛系統(tǒng)中使用C的指南,稱為MISRA
C~自那時以來,該指南一直在不斷完善,并不時發(fā)布更新。還建立了類似的使用C++的方法。雖然該指南最初是針對汽車用軟件的嵌入式開發(fā)人員,但很快就意識到,它們同樣適用于安全性至關重要的許多其他應用領域,并且該標準現(xiàn)在已在許多行業(yè)中廣泛采用。
盡管MISRA
C不是一個樣式指南——事實上,許多用戶應用了樣式指南和標準——但許多規(guī)則也促進了清晰易讀的可維護代碼的編寫。這是非常有益的,因為易于理解的代碼不太可能隱藏細微的錯誤或未定義的行為。
我將在這里簡單介紹一下指南。MisraC正在不斷地進行審查,不斷地修改指南的清晰性和準確性,并支持更新版本的C語言標準。盡管細節(jié)發(fā)生了變化,但總體理念和方法沒有變化。
規(guī)則13.2–在所有允許的評估順序下,表達式的值及其持續(xù)性副作用應相同
C語言標準在表達式的求值順序方面為編譯器提供了非常廣泛的自由度。因此,在嵌入式開發(fā)中,任何對求值順序敏感的代碼都依賴于編譯器,并且依賴于編譯器的代碼應始終被視為不安全的。
規(guī)則17.2——職能部門不得直接或間接地調(diào)用自己
有時,表達算法的一種優(yōu)雅方式是使用遞歸。但是,除非遞歸受到非常嚴格的控制,否則存在堆棧溢出的危險,這反過來會導致很難找到bug。在安全關鍵代碼中,應避免遞歸。
規(guī)則19.2–不應使用union關鍵字
盡管C是一種類型化語言,但類型化并不是很嚴格,開發(fā)人員可能會試圖覆蓋類型化來“簡化”代碼。遵守數(shù)據(jù)類型的約束對于創(chuàng)建安全代碼至關重要,因為任何繞過數(shù)據(jù)類型的嘗試都可能產(chǎn)生未定義的結果。union關鍵字可以用于多種目的,通常會導致代碼不清晰,但也可以作為避免鍵入的一種手段。
有人可能會爭辯說,這些規(guī)則(以及MisraC的大部分,如果不是全部的話)只是常識,任何優(yōu)秀的嵌入式開發(fā)人員都會采用這種方法。這可能是真的,但一套明確的指導方針讓機會更少了。