剖析ASSERT函數


蒐集與總結了assert函數的用法,記於此,以備後續與查找使用:
****身在Windows的世界,但仍是深愛着個人它---Linux****I love Linux forever*****
****先給一個小例子,熱熱身*********Never give up **************

請看下面的程序清單badptr.c:php

#includeexpress

#include編程

#includeapp

int main( void )函數

{性能

FILE *fp;測試

fp = fopen( "test.txt", "w" );//以可寫的方式打開一個文件,若是不存在就建立一個同名文件ui

assert( fp ); //因此這裏不會出錯this

fclose( fp );編碼

fp = fopen( "noexitfile.txt", "r" );//以只讀的方式打開一個文件,若是不存在就打開文件失敗

assert( fp ); //因此這裏出錯

fclose( fp ); //程序永遠都執行不到這裏來

return 0;

}

[root@localhost error_process]# gcc badptr.c

[root@localhost error_process]# ./a.out

a.out: badptr.c:14: main: Assertion `fp' failed.

已放棄

使用assert的缺點是,頻繁的調用會極大的影響程序的性能,增長額外的開銷。

在調試結束後,能夠經過在包含#include的語句以前插入 #define NDEBUG 來禁用assert調用,示例代碼以下:

#include

#define NDEBUG

#include

用法總結與注意事項:

1)在函數開始處檢驗傳入參數的合法性

如:

int resetBufferSize(int nNewSize)

{

//功能:改變緩衝區大小,

//參數:nNewSize 緩衝區新長度

//返回值:緩衝區當前長度

//說明:保持原信息內容不變 nNewSize<=0表示清除緩衝區

assert(nNewSize >= 0);

assert(nNewSize <= MAX_BUFFER_SIZE);

...

}

2)每一個assert只檢驗一個條件,由於同時檢驗多個條件時,若是斷言失敗,沒法直觀的判斷是哪一個條件失敗

很差: assert(nOffset>=0 && nOffset+nSize<=m_nInfomationSize);

好: assert(nOffset >= 0);

assert(nOffset+nSize <= m_nInfomationSize);

3)不能使用改變環境的語句,由於assert只在DEBUG個生效,若是這麼作,會使用程序在真正運行時遇到問題

錯誤: assert(i++ < 100)

這是由於若是出錯,好比在執行以前i=100,那麼這條語句就不會執行,那麼i++這條命令就沒有執行。

正確: assert(i < 100)

i++;

4)assert和後面的語句應空一行,以造成邏輯和視覺上的一致感

5)有的地方,assert不能代替條件過濾。


  assert宏的原型定義在<assert.h>中,其做用是若是它的條件返回錯誤,則終止程序執行,原型定義: 
#include <assert.h> 
void assert( int expression ); 

assert的做用是現計算表達式 expression ,若是其值爲假(即爲0),那麼它先向stderr打印一條出錯信息, 
而後經過調用 abort 來終止程序運行。 

http://www.chongtang.me/index.php/1419

提升程序健壯性之assert使用

編寫能正常運行的程序很難;編寫在錯誤狀況下仍然表現的很「優雅」的程序更難。這篇文章將和你們討論一些編程技巧,可使咱們在運行中的程序中早點發現錯誤,檢測和從問題中恢復。那就先討論下斷言(assert)的使用吧。

在編碼時,有一個好的目標應該時刻銘記在心,那就是:應該想辦法讓bug或者異常錯誤儘早使得程序down掉,或者出現錯誤。由於這樣能夠幫助你在開發和測試階段儘快找出bug。有一些錯誤不會平白無故的暴露本身,每每是產品都到了客戶手上,這些錯誤纔會顯現出來。

一個最簡單的檢查異常條件的方法是使用標準C的assert宏,它的參數是一個bool表達式。當表達式爲假時,程序會退出。在退出以前打印錯誤消息,包括源文件,行號,和表達式自己。斷言很是有用,它提供了一個做用於程序內部的普遍的一致性檢查方法。例如,使用斷言測試函數參數的有效性,測試異常的返回值等等。

每個斷言的使用不只提供了一個程序運行時的條件檢查,也像一個對源代碼級別的程序操做的說明性文檔。若是你的程序包含了一個斷言,也就是告訴那些閱讀你源代碼的人,在你的源代碼中,在程序的這一點,這個條件應該爲真,若是不爲真,那就是一個bug。

固然,在追求性能的代碼中,使用assert會下降程序性能。可是你放心,在編譯時加入NDEBUG參數編譯器就能夠對assert進行預處理,從而移除它。正由於在預處理時可能移除assert,那你使用時就得當心了。何時用,何時不用就成了一個問題。一般,你不該該在assert內部調用函數,定義變量,或者使用改變值的操做符,如++。

咱們假設你這樣使用了:

for (i = 0; i &lt;= 100; ++i) assert (do_something () == 0);

而後,你可能會發現這樣會使得性能大大下降,從而在創新編譯使使用NDEGUG參數。這將移除整個assert宏,這就將do_something( )也被移除了,不再被調用。爲了糾正錯誤,你應該這樣寫:

for (i = 0; i &lt;= 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);,這將幫助你檢測函數的錯誤使用,這也給源代碼閱讀者很清晰的印象,那就是在這裏對函數的參數值有限制。

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



---------------------------------------------------------------   

ASSERT()是一個調試程序時常用的宏,在程序運行時它計算括號內的表達式,若是表達式爲FALSE  (0),  程序將報告錯誤,並終止執行。若是表達式不爲0,則繼續執行後面的語句。這個宏一般原來判斷程序中是否出現了明顯非法的數據,若是出現了終止程序以避免致使嚴重後果,同時也便於查找錯誤。   

ASSERT只有在Debug版本中才有效,若是編譯爲Release版本則被忽略。   
---------------------------------------------------------------   

ASSERT宏定義以下   

#define  ASSERT(f)  \   
do  \   
{  \   
      if  (!(f)  &&  AfxAssertFailedLine(THIS_FILE,  __LINE__))  \   
              AfxDebugBreak();  \   
}  while  (0)  \   

ASSERT(邏輯表達式)   

若是括號中的邏輯表達式值爲假的話,會彈出調試命令窗口,提示具體在哪一個文件的哪一行發生了斷言錯誤!   
---------------------------------------------------------------   

ASSERT   
Evaluates  an  expression,  and  displays  a  diagnostic  message  if  the  expression  is  FALSE.  Ignored  in  retail  builds.   

Syntax   

ASSERT(   
      cond   
);   

Parameters   

cond   

Expression  to  evaluate.   

Remarks   

In  debug  builds,  if  the  expression  is  FALSE,  this  macro  displays  a  message  box  with  the  text  of  the  expression,  the  name  of  the  source  file,  and  the  line  number.  The  user  can  ignore  the  assertion,  enter  the  debugger,  or  quit  the  application.   

Example   

ASSERT(rtStartTime  <=  rtEndTime);   


---------------------------------------------------------------   

斷言(ASSERT)的使用,方法很簡單。爲何要用,初學者可能比較迷惑。   
契約式編程講的比較清楚,建議能夠先看看這類書。   
一個函數由前置條件、後置條件和不變式組成。在VC中,咱們能夠經過斷言來保證這三個條件。能夠大大提升了軟件的質量。   
---------------------------------------------------------------   

若是ASSERT()中的條件不成立(好比  ASSERT(0)  ;    ),會彈出一個比較嚇人的對話框。   

點擊重試,能夠到達  ASSERT  斷言不成立的那一行,   

此時能夠在watch窗口查看變量值,找出出錯的緣由。   

相關文章
相關標籤/搜索