嵌入式開發(fā)人員可用的最強大的錯誤壓縮工具之一是斷言宏。盡管斷言很強大,但卻很少看到它被實現(xiàn),并且在使用它的情況下,實現(xiàn)要么有缺陷,要么不正確。以下七個技巧不僅有助于闡明何時何地使用斷言,而且還有助于闡明如何開始正確使用它。
技巧1 – 記住斷言的定義
斷言對于許多開發(fā)人員來說是一個令人困惑的話題,因為他們很容易以一種并非設(shè)計用于的方式使用斷言。 關(guān)于斷言的最清晰定義是:“斷言是程序中特定點的布爾表達式,除非程序中存在錯誤,否則它將為真。”
檢查上述斷言定義的開發(fā)人員應(yīng)注意三個關(guān)鍵點:
斷言將表達式評估為真或假
斷言是對代碼中特定點的系統(tǒng)狀態(tài)的假設(shè)
斷言正在驗證系統(tǒng)假設(shè),如果不正確,則表明代碼中存在錯誤
技巧2 – 使assert來驗證函數(shù)的前置條件
斷言在按合同設(shè)計的環(huán)境中工作得很好,其中嵌入式開發(fā)人員已經(jīng)明確定義了函數(shù)的先決條件。 斷言可用于檢查函數(shù)的輸入是否滿足前提條件。以下代碼片段為例:
函數(shù)的狀態(tài)輸入應(yīng)屬于定義的系統(tǒng)狀態(tài)。如果 State 在有效狀態(tài)之外,那不是錯誤而是bug!斷言可用于驗證狀態(tài)有效的假設(shè),如下圖所示:
如果狀態(tài)不小于最大值,則斷言表達式將被評估為假,然后程序執(zhí)行將停止。 停止程序執(zhí)行使開發(fā)人員可以很容易地立即看到代碼出錯的地方,而不是等很久以后。
技巧3 – 使用斷言來驗證函數(shù)的后置條件
斷言還可用于驗證有關(guān)按合同設(shè)計環(huán)境中函數(shù)輸出的假設(shè)。例如,如果先前定義的System_StateSet 函數(shù)返回 SystemState 變量,開發(fā)人員會期望它也在預(yù)期范圍內(nèi)。可以使用斷言來監(jiān)視錯誤,如下圖所示:
檢查上面的代碼,嵌入式開發(fā)人員可能會覺得這些檢查毫無價值。剛剛設(shè)置的 SystemState怎么會大于 SYSTEM_STATE_MAX?答案是它不應(yīng)該是這樣,這就是為什么如果它確實發(fā)生了變化,可能是通過中斷或并行線程,斷言將立即標記錯誤。
技巧4 – 不要使用斷言進行錯誤處理
在記住斷言的定義后,開發(fā)人員應(yīng)該牢記斷言是用于檢測錯誤而不是用于錯誤處理。錯誤處理是旨在響應(yīng)不正確的用戶輸入和意外事件序列的軟件。錯誤預(yù)計會在系統(tǒng)中發(fā)生,但僅僅因為輸入無效并不意味著代碼中存在錯誤。錯誤處理應(yīng)與錯誤搜尋分開。不正確使用斷言的一個典型例子是在嘗試打開文件進行讀取時檢查文件指針。圖4顯示了一個示例。
讀者可以清楚地看到,嘗試打開文件的結(jié)果取決于文件系統(tǒng)和用戶數(shù)據(jù)的狀態(tài),與代碼中的錯誤完全無關(guān)。而不是斷言,嵌入式開發(fā)人員應(yīng)該編寫一個錯誤處理程序,如果文件不存在,它會創(chuàng)建它,它將一些默認的可用數(shù)據(jù)用于進一步發(fā)生在代碼中的操作。
技巧5 – 斷言用于開發(fā)而非生產(chǎn)
斷言宏的初衷是在開發(fā)期間啟用它,然后在生產(chǎn)中禁用它。啟用和禁用斷言是使用宏 NDEBUG 完成的。正確實現(xiàn)的斷言在禁用時應(yīng)該對嵌入式系統(tǒng)幾乎沒有影響。問題是,如果在開啟它們的情況下執(zhí)行測試,應(yīng)該這樣做以捕獲任何錯誤,現(xiàn)在關(guān)閉它們會導致交付的產(chǎn)品處于與測試狀態(tài)不同的狀態(tài)。
斷言確實占用了一些代碼空間,但更重要的是它們需要幾個時鐘周期來評估它們的布爾表達式。資源有限的裸機系統(tǒng)可能會因關(guān)閉斷言而嚴重影響其執(zhí)行時間,從而導致生產(chǎn)系統(tǒng)中出現(xiàn)新的錯誤。開發(fā)團隊需要決定是否值得承擔風險。另一種方法是啟用斷言并將其輸出重定向到系統(tǒng)日志,以便輕松識別任何揮之不去的錯誤,但可能不建議暫停系統(tǒng)。
技巧6 – 不要讓斷言產(chǎn)生副作用
assert 的默認實現(xiàn)將允許嵌入式開發(fā)人員將可執(zhí)行代碼作為布爾表達式的一部分包含在內(nèi)。例如,狀態(tài)變量可以作為傳遞給 assert 的表達式的一部分來實現(xiàn)。如果傳遞給 assert 的表達式有副作用,即它改變了嵌入式系統(tǒng)的狀態(tài),禁用斷言將改變系統(tǒng)的行為。開發(fā)人員應(yīng)確保他們的表達式?jīng)]有副作用,因為他們可能會在系統(tǒng)中添加睡眠時間錯誤,該錯誤只會喚醒生產(chǎn)代碼。
技巧7 – 斷言應(yīng)該占代碼的1 % — 3%
對于代碼庫中應(yīng)該存在多少斷言,每個開發(fā)人員都有自己的看法。可以商定的一個數(shù)字是代碼庫中斷言的百分比應(yīng)該大于零。斷言為開發(fā)人員提供了一種在代碼庫中出現(xiàn)錯誤時發(fā)現(xiàn)錯誤的好方法。調(diào)試是開發(fā)嵌入式系統(tǒng)最大的浪費時間和令人沮喪的組件之一。無論開發(fā)人員的人數(shù)是1%、3%還是5%,都可以利用斷言來發(fā)揮自己的優(yōu)勢,讓開發(fā)嵌入式軟件變得更加愉快。如果有的話,我們知道有 0% 不是正確的解決方案!
技巧8 – 使用斷言作為可執(zhí)行代碼注釋
斷言會產(chǎn)生很好的評論!一個寫得很好的表達式可以準確地告訴開發(fā)人員他們在代碼中的給定點應(yīng)該期望什么。開發(fā)人員應(yīng)該構(gòu)建他們的斷言,以便更清楚地了解系統(tǒng)中正在發(fā)生的事情,這反過來將有助于減少錯誤。
結(jié)論
斷言是一個了不起的工具,被太多的嵌入式開發(fā)人員忽略了。本文探討的 7 個技巧只是如何正確使用斷言的冰山一角。你可以采取的下一步是在測試臺上設(shè)置并開始使用斷言,并研究它們在真實嵌入式系統(tǒng)中的工作方式。