assert和if使用的環境及使用場景

*assert還是if


在剛開始學習代碼的時候,對於程序中檢查程序有效性時有時用到assert,有時用if,感到非常困惑。比如,在多數的malloc函數後面對指針進行的操作都是用assert進行檢查的,可能會造成一種錯覺以爲在malloc之後對申請空間的檢測是用assert進行的,但可能也會看到用if對malloc進行判斷並處理,到底是if還是assert呢?

以下是庫中關於assert的定義,我將其他一些地方去掉了:

#ifdef  NDEBUG
#define assert(_Expression)     ((void)0)
#else
#define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )
#endif

上面是在庫中關於assert的定義,NDEBUG爲非調試模式,即release模式。可以看到,在Release模式下assert宏什麼事情都沒有幹,但是在debug模式下,如果表達式的值爲0,則輸出消息並終止程序的執行。表達式爲真時不會進行任何操作,所以斷言失敗,就表明程序存在bug,出現了預期不應該出現的情況。也就是說在release模式下,assert宏相當於不存在了.

 

assert是用來發現運行時刻的錯誤,發現的錯誤是關於程序實現方面的。使用斷言最根本的好處是自動發現許多運行時產生的錯誤,能在產生錯誤的發源地發現錯誤,以便程序員很快的找到錯誤並對其做出處理。

assert一般用與檢查函數參數的合法性(有效性)而不是正確性,但是合法的程序並不見得就是正確的程序。參數爲NULL或者沒有進行初始化,這些都是會導致程序不能正常運行的非法情況。使用assert的目的是捕捉在運行時不應該發生的非法情況。不要混淆非法情況與錯誤情況之間的區別,前者是程序員不願意看到的會導致程序不能正常運行的情況;後者是程序運行過程中自然存在的並且是一定要主動做出處理的情況。比如說對於一個磨麪粉的機器來說,出現了異常沒有磨出麪粉,第一種情況是磨面機由於電動機出現問題,使得電源關閉沒有出面粉;另一種情況是我們裝入的原料是玉米而不是麥子,這樣我們同樣得不到麪粉。當然第一種情況是誰都不願意看到的一旦其發生會引起麪粉機異常(終止),而第二種情況我們做一些操作就是可以處理的。

舉例1:

bool fun(ptype* p)
{
    assert(p);

    ……
}

說了這麼多,那對於上面的例子,究竟是用if呢還是assert呢?試着分析下:上課時我們講過,指針並不是在什麼情況下都需要判斷是否爲NULL,這要看具體的場景,比如指向鏈表第一個有效結點的指針,如果鏈表中一個節點都沒有時該指針便指向NULL,這是一種合法的情況,所以就不能使用assert來斷言。  當你確信該指針爲NULL爲一種非法情況,在你的程序中本不應該出現,如果出現就說明你程序某處存在bug。也就是說在你調用該函數的過程中,程序邏輯上存在某些錯誤,此時用assert斷言,那麼它將會非常不高興,怒氣衝衝的打斷程序執行流,指着鼻子告訴你NULL指針問題,你就需要抓小蟲子了(即Debug),所以assert方便我們調試定位排查問題;而此時如果使用if呢,程序可能會繼續往下執行,不會將錯誤拋出,此bug就被隱藏起來了,說不定哪天就會爆發,當真的爆發時哪可能就是一場災難,如果此bug隱藏的比較深,對於我們排查起來那是相當相當困難的。

 

舉例2;

void fun()
{
    int* p = (int*)malloc(sizeof(int));
    assert(p);
}

    這裏是斷言的一個錯誤用法,p爲一個申請了內存的指針,申請內存就有存在申請失敗的可能,這時malloc會返回NULL,這種情況是存在的,不屬於程序運行過程中產生的非法情況,所以最好使用if來判斷。

  有些時候,針對於防禦性編程,你可能會看到這麼做:

void fun()
{
  int* p = (int*)malloc(sizeof(int));
  if(NULL == p)
     assert(p);
}

總結:

1、assert是調試宏而不是一個函數,只在debug纔有效。

2、使用assert來捕捉程序運行過程中出現的非法情況,在你的程序中,假如某種情況肯定不會出現,如果出現,就說明你的程序在某塊存在錯誤,此時最好用assert斷言,比如除法時除數不爲0;而該情況可能會出現且是合法情況,此時最好用if來判斷,比如malloc空間時。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章