1. 程式人生 > >ASSERT函式

ASSERT函式

編寫能正常執行的程式很難;編寫在錯誤情況下仍然表現的很“優雅”的程式更難。這篇文章將和大家討論一些程式設計技巧,可以使我們在執行中的程式中早點發現錯誤,檢測和從問題中恢復。那就先討論下斷言(assert)的使用吧。

在編碼時,有一個好的目標應該時刻銘記在心,那就是:應該想辦法讓bug或者異常錯誤儘早使得程式down掉,或者出現錯誤。因為這樣可以幫助你在開發和測試階段儘快找出bug。有一些錯誤不會無緣無故的暴露自己,往往是產品都到了客戶手上,這些錯誤才會顯現出來。

一個最簡單的檢查異常條件的方法是使用標準C的assert巨集,它的引數是一個bool表示式。當表示式為假時,程式會退出。在退出之前列印錯誤訊息,包括原始檔,行號,和表示式本身。斷言非常有用,它提供了一個作用於程式內部的廣泛的一致性檢查方法。例如,使用斷言測試函式引數的有效性,測試異常的返回值等等。

每一個斷言的使用不僅提供了一個程式執行時的條件檢查,也像一個對原始碼級別的程式操作的說明性文件。如果你的程式包含了一個斷言,也就是告訴那些閱讀你原始碼的人,在你的原始碼中,在程式的這一點,這個條件應該為真,如果不為真,那就是一個bug。

當然,在追求效能的程式碼中,使用assert會降低程式效能。但是你放心,在編譯時加入NDEBUG引數編譯器就可以對assert進行預處理,從而移除它。正因為在預處理時可能移除assert,那你使用時就得小心了。什麼時候用,什麼時候不用就成了一個問題。通常,你不應該在assert內部呼叫函式,定義變數,或者使用改變值的操作符,如++。

我們假設你這樣使用了:

for (i = 0; i <= 100; ++i) assert (do_something () == 0);

然後,你可能會發現這樣會使得效能大大降低,從而在創新編譯使使用NDEGUG引數。這將移除整個assert巨集,這就將do_something( )也被移除了,再也不被呼叫。為了糾正錯誤,你應該這樣寫:

for (i = 0; i <= 100; ++i) { int status = do_something (); assert (status == 0); }

另外應該銘記在心的是,不要用assert去檢查無效的輸入。使用者可不喜歡自己在輸入時程式直接退出,即便是輸入錯誤,程式最好也有友好的響應。所以,你應該對無效輸入進行檢查,並輸出一些有用的提示資訊。只在程式執行中進行內部檢查時使用斷言。

在這裡,我會給出一些比較好的在程式中使用assert的地方:

(1)空指標檢查。例如,針對一個函式的引數進行空指標檢查。你可以這樣使用:assert (pointer != NULL);,產生的錯誤會像這樣:Assertion ‘pointer != ((void *)0)’ failed。這樣,當出現空指標時,你的程式就會退出,並很好的給出錯誤資訊。

(2)檢查函式引數的值。例如,如果一個函式只能在它的一個引數foo為正值的時候被呼叫,你可以在函式開始時這樣寫:assert (foo > 0);,這將幫助你檢測函式的錯誤使用,這也給原始碼閱讀者很清晰的印象,那就是在這裡對函式的引數值有限制。

說了這麼多,行動起來吧,大膽的在你的程式中使用斷言。