assert還是if
專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、外貿(mào)網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)文峰免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了成百上千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。在剛開始學(xué)習(xí)代碼的時(shí)候,對(duì)于程序中檢查程序有效性時(shí)有時(shí)用到assert,有時(shí)用if,感到非常困惑。比如,在多數(shù)的malloc函數(shù)后面對(duì)指針進(jìn)行的操作都是用assert進(jìn)行檢查的,可能會(huì)造成一種錯(cuò)覺以為在malloc之后對(duì)申請(qǐng)空間的檢測(cè)是用assert進(jìn)行的,但可能也會(huì)看到用if對(duì)malloc進(jìn)行判斷并處理,到底是if還是assert呢?
以下是庫中關(guān)于assert的定義,我將其他一些地方去掉了:
#ifdef NDEBUG
#define assert(_Expression) ((void)0)
#else
#define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )
#endif
上面是在庫中關(guān)于assert的定義,NDEBUG為非調(diào)試模式,即release模式??梢钥吹?,在Release模式下assert宏什么事情都沒有干,但是在debug模式下,如果表達(dá)式的值為0,則輸出消息并終止程序的執(zhí)行。表達(dá)式為真時(shí)不會(huì)進(jìn)行任何操作,所以斷言失敗,就表明程序存在bug,出現(xiàn)了預(yù)期不應(yīng)該出現(xiàn)的情況。也就是說在release模式下,assert宏相當(dāng)于不存在了.
assert是用來發(fā)現(xiàn)運(yùn)行時(shí)刻的錯(cuò)誤,發(fā)現(xiàn)的錯(cuò)誤是關(guān)于程序?qū)崿F(xiàn)方面的。使用斷言最根本的好處是自動(dòng)發(fā)現(xiàn)許多運(yùn)行時(shí)產(chǎn)生的錯(cuò)誤,能在產(chǎn)生錯(cuò)誤的發(fā)源地發(fā)現(xiàn)錯(cuò)誤,以便程序員很快的找到錯(cuò)誤并對(duì)其做出處理。
assert一般用與檢查函數(shù)參數(shù)的合法性(有效性)而不是正確性,但是合法的程序并不見得就是正確的程序。參數(shù)為NULL或者沒有進(jìn)行初始化,這些都是會(huì)導(dǎo)致程序不能正常運(yùn)行的非法情況。使用assert的目的是捕捉在運(yùn)行時(shí)不應(yīng)該發(fā)生的非法情況。不要混淆非法情況與錯(cuò)誤情況之間的區(qū)別,前者是程序員不愿意看到的會(huì)導(dǎo)致程序不能正常運(yùn)行的情況;后者是程序運(yùn)行過程中自然存在的并且是一定要主動(dòng)做出處理的情況。比如說對(duì)于一個(gè)磨面粉的機(jī)器來說,出現(xiàn)了異常沒有磨出面粉,第一種情況是磨面機(jī)由于電動(dòng)機(jī)出現(xiàn)問題,使得電源關(guān)閉沒有出面粉;另一種情況是我們裝入的原料是玉米而不是麥子,這樣我們同樣得不到面粉。當(dāng)然第一種情況是誰都不愿意看到的一旦其發(fā)生會(huì)引起面粉機(jī)異常(終止),而第二種情況我們做一些操作就是可以處理的
舉例1:
bool fun(ptype* p)
{
assert(p);
……
}
說了這么多,那對(duì)于上面的例子,究竟是用if呢還是assert呢?試著分析下:上課時(shí)我們講過,指針并不是在什么情況下都需要判斷是否為NULL,這要看具體的場(chǎng)景,比如指向鏈表第一個(gè)有效結(jié)點(diǎn)的指針,如果鏈表中一個(gè)節(jié)點(diǎn)都沒有時(shí)該指針便指向NULL,這是一種合法的情況,所以就不能使用assert來斷言。 當(dāng)你確信該指針為NULL為一種非法情況,在你的程序中本不應(yīng)該出現(xiàn),如果出現(xiàn)就說明你程序某處存在bug。也就是說在你調(diào)用該函數(shù)的過程中,程序邏輯上存在某些錯(cuò)誤,此時(shí)用assert斷言,那么它將會(huì)非常不高興,怒氣沖沖的打斷程序執(zhí)行流,指著鼻子告訴你NULL指針問題,你就需要抓小蟲子了(即Debug),所以assert方便我們調(diào)試定位排查問題;而此時(shí)如果使用if呢,程序可能會(huì)繼續(xù)往下執(zhí)行,不會(huì)將錯(cuò)誤拋出,此bug就被隱藏起來了,說不定哪天就會(huì)爆發(fā),當(dāng)真的爆發(fā)時(shí)哪可能就是一場(chǎng)災(zāi)難,如果此bug隱藏的比較深,對(duì)于我們排查起來那是相當(dāng)相當(dāng)困難的。
舉例2;
void fun()
{
int* p = (int*)malloc(sizeof(int));
assert(p);
}
這里是斷言的一個(gè)錯(cuò)誤用法,p為一個(gè)申請(qǐng)了內(nèi)存的指針,申請(qǐng)內(nèi)存就有存在申請(qǐng)失敗的可能,這時(shí)malloc會(huì)返回NULL,這種情況是存在的,不屬于程序運(yùn)行過程中產(chǎn)生的非法情況,所以最好使用if來判斷。 有些時(shí)候,針對(duì)于防御性編程,你可能會(huì)看到這么做:void fun()
{
int* p = (int*)malloc(sizeof(int));
if(NULL == p)
assert(p);
}
總結(jié):
1、assert是調(diào)試宏而不是一個(gè)函數(shù),只在debug才有效。
2、使用assert來捕捉程序運(yùn)行過程中出現(xiàn)的非法情況,在你的程序中,假如某種情況肯定不會(huì)出現(xiàn),如果出現(xiàn),就說明你的程序在某塊存在錯(cuò)誤,此時(shí)最好用assert斷言,比如除法時(shí)除數(shù)不為0;而該情況可能會(huì)出現(xiàn)且是合法情況,此時(shí)最好用if來判斷,比如malloc空間時(shí)。
創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務(wù)器,動(dòng)態(tài)BGP最優(yōu)骨干路由自動(dòng)選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨(dú)有T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動(dòng)現(xiàn)已開啟,新人活動(dòng)云服務(wù)器買多久送多久。