您好,登錄后才能下訂單哦!
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空間時。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。