Path: EDNTaiwan電子技術設計 >> 設計中心 >> IC/電路板/系統設計 >> 正確使用ASSERT捕捉程式缺陷的八個技巧
IC/電路板/系統設計 Share print

正確使用ASSERT捕捉程式缺陷的八個技巧

2015年12月23日  | Jacob Beningo

Share this page with your friends

C語言中的ASSERT巨集(macro)是嵌入式軟體發展人員可以使用的最好的缺陷捕捉(bug-squashing)工具之一。雖然ASSERT功能強大,但我很少看到成功的實作,在一些使用到的案例中,它的實作也經常是有瑕疵或不正確的。


以下一些技巧不僅有助於開發人員瞭解該在何時、在哪裡使用ASSERT,而且可以幫助他們學會如何開始正確地使用ASSERT。


技巧1:記住ASSERT的定義

對許多開發人員來說ASSERT是容易讓人困惑的課題,因為他們的許多使用方式與設計ASSERT的初衷背道而馳。我見過最清楚的ASSERT定義是這樣的:「ASSERT是位於程式某個特定點的一個布林運算式(Boolean),除非程式中有缺陷,否則它的值一直為真。」


想要理解上述ASSERT定義的開發人員應該留意下面三個要點:


  ●  ASSERT會評估一個運算式是真還是假。

  ●  ASSERT是在程式碼中的某個點對系統狀態的一種假設。

  ●  ASSERT會驗證系統假設,如果不為真,就揭示了程式碼中的一個缺陷。

技巧2:使用ASSERT驗證函數的先決條件

ASSERT非常適合契約式設計(design-by-contract)環境,在這種環境中,開發人員非常清晰地定義了某個函數的先決條件。ASSERT可以用來檢查該函數的輸入是否滿足先決條件要求;就拿圖1所示的程式碼片段為例。


圖1 函數的先決條件。
圖1 函數的先決條件。

函數的State輸入應該在定義好的系統狀態範圍內。如果State不是有效的狀態值,那麼它就不是差錯,而是缺陷!ASSERT可以用來驗證State是有效的假設,如圖2所示。


圖2對函數先決條件應用ASSERT。
圖2對函數先決條件應用ASSERT。

當發生State不小於最大值的事件時,ASSERT運算式的值將被評估為假,程式將停止執行。停止程式的執行可以讓開發人員很容易馬上看到哪裡的程式碼出錯,而不是過段時間以後才知道。


技巧3:使用ASSERT驗證函數的後置條件

ASSERT也能用來驗證契約式設計環境中對某個函數輸出的假設。舉例來說,前面定義的System_State-Set函數返回的SystemState變數是否也在開發人員期望的範圍之內。ASSERT可以用作缺陷監視器,如圖3所示。


圖3 對函數後置條件應用ASSERT。
圖3 對函數後置條件應用ASSERT。

開發人員在查看上述程式碼後可能會感到這些檢查毫無意義。剛剛才設置好的SystemState怎麼會出現大於SYSTEM_STATE_MAX的值呢?答案是雖然確實不應該出現,但有時候會莫名其妙地發生改變,也許是透過中斷或平行執行緒,此時ASSERT可以立即標記出這種缺陷。


技巧4:不要把ASSERT用於錯誤處理

在記住ASSERT定義之後,開發人員應該切記:ASSERT是用於檢測缺陷的,不能用於錯誤處理(error handling)。錯誤處理是設計用於回應錯誤的使用者輸入和意外的事件順序的軟體;錯誤在系統中是預料會發生的,但僅僅因為是無效的輸入並不意味著程式碼存在缺陷。


錯誤處理應該與缺陷捕捉分開來;不當使用ASSERT的一個典型例子是,在試圖打開一個檔案讀取其中內容時,又去檢查檔案指標(file pointer),如圖4所示。


圖4 ASSERT的不當使用。
圖4 ASSERT的不當使用。

讀者可以清楚地看到,試圖打開檔案的結果與檔案系統的狀態和使用者資料有關,與程式碼中的缺陷一點關係也沒有。與ASSERT不同,開發人員應該編寫錯誤處理常式,以便在檔案不存在時,錯誤處理常式(error handler)可以用一些預設用資料創建這樣的檔案,以便後續程式碼繼續運作。


技巧5:ASSERT是為了開發而非生產

開發ASSERT巨集的原始意圖是在開發過程中使用它,在後續的生產過程要禁用;啟用與禁用ASSERT可以透過NDEBUG巨集。正確實作的ASSERT在被禁用後應該基本上對嵌入式系統沒有影響。


問題是,如果測試是在ASSERT啟動的情況下進行的(為了捕捉任何缺陷,應該這樣做),那麼現在禁用這些ASSERT將導致交付的產品與測試的產品處於不同的狀態。


ASSERT確實會佔用一些程式碼空間,但更重要的是它們需要佔用少量的時脈週期來評估它們的布林運算式。禁用ASSERT可能對資源有限的裸機系統執行時序有很大的影響,導致在量產的系統中產生新的缺陷。開發小組需要判斷是否值得冒險關閉ASSERT。


一種替代方案是維持ASSERT在啟動狀態,但將它們的輸出重定向到系統日誌。這樣可以確保任何揮之不去的缺陷很容易被識別,而且能避免中止系統的運作,而中止系統可不是明智之舉。


技巧6:不允許ASSERT有副作用

ASSERT的預設實作允許開發人員包含一段可執行程式碼作為布林運算式的一部分。舉例來說,一個狀態變數(state variable)可以被實作為運算式的一部分並傳遞給ASSERT。


但如果傳遞給ASSERT的運算式有副作用,也就是說,它會改變嵌入式系統的狀態,那麼禁用ASSERT將改變系統的行為。開發人員應該確保他們的運算式沒有副作用,否則他們就可能冒著在系統添加一個只會被量產程式碼喚醒的待機時間缺陷風險。


技巧7:ASSERT應該佔程式碼的1~3%

對於程式碼基底(code base)中應該有多少ASSERT,每個開發人員都有自己的主見;大家一致同意的一個數字是,程式碼基底中的ASSERT比例應該超過0%。


ASSERT為開發人員提供了發現程式碼基底缺陷的極好方式;畢竟除錯是在開發嵌入式系統中最浪費時間並令人沮喪的事情之一。不管開發人員認可的比例是1%、3%還是5%,使用ASSERT肯定對你有利,並使開發嵌入式軟體變得更有點樂趣。


技巧8:將ASSERT用作可執行的程式碼註解

ASSERT可以生成極佳的註解!編寫出色的運算式可以確切地告訴開發人員在程式碼的某個既定點應該期望發生什麼事情。開發人員應該做好ASSERT的架構,幫助人們更清楚地理解系統中發生的事情,進而有助於減少缺陷。


小結

ASSERT是一種出色的工具,但有太多的嵌入式軟體開發人員忽視了它。本文討論的八個技巧僅是如何正確使用ASSERT之皮毛,讀者接下來可以在測試平台上設定和開始使用ASSERT,並研究它們在實際的嵌入式系統中如何運作。





想要免費接收更多的技術設計資訊嗎?

馬上訂閱《電子技術設計》郵件速遞,透過郵箱輕鬆接收最新的設計理念和產品新聞。

為確保您的資訊安全,請輸入右方顯示的代碼.

啟動您的訂閱申請

我們已給您的註冊郵箱發送了確認信,請點擊信中的連結啟動您的訂閱申請。

這將有助於我們很好地保護您的個人隱私同時確保您能成功接收郵件。


添加新評論
遊客 (您目前以遊客身份發表,請 登入 | 註冊)
*驗證碼:

新聞 | 產品 | 設計實例