http://bdn.borland.com/article/0,1410,28432,00.html
摘要:assert()調用允許你測試代碼中的問題,但它有些局限。本文詳述了一個改進的assert調用。
改進的C++ Builder assert()
做為良好編程的一部分,您代碼中的斷言是監視正在發生了什麼的一種簡捷的途徑。本文討論給assert()增加靈活性,使其變得更有用。
斷言的一些背景
多年來,我一直使用assert()管理代碼。
assert(int test)
這個函數獲得test,斷言test結果為真——如果為真,什麼也不做,否則產生一個警告,允許您的程式方便地檢測錯誤。assert()的好處是它也是一個宏,如果你#define NDEBUG,這些宏從您的代碼消失,什麼也不留下。
在檢查代碼很有用的同時,assert()自身也有一些問題:
失敗的斷言預設是跳出程式,一個警告出現測試就結束。
在每次到達時,assert()都要檢查,這使得在迴圈中難以使用。
很難檢查代碼,因為assert()通常調用abort(),忽略斷言繼續調試就不可能。
ASSERTING()
當然,這些問題正是本文要解決的。通過修改assert(),我們得到驗證代碼更健壯更有用的方式。結果是一個我稱之為ASSERTING()的宏包,即和代碼脫離,又區別於assert(). 它包含在例子代碼的assert2.cpp/.dfm/.h檔案中:
ASSERTING(int test,char *errorMessage)
和正常的assert()一樣,NDEBUG決定這代碼是否被實際建立。它還添加了一個解釋資訊以有助於理解錯誤。
標頭檔的宏表明它應該如何被處理。如果NDEBUG沒有被定義,在每個ASSERTING()調用時下列代碼將被展開。
#define ASSERTING(test,msg)
{
if (!(test))
{
static int callIt=1;
if (callIt)
{
if (HandleAsserting(#test,#msg,__FILE__,__LINE__,&callIt))
{ _asm { int 3 } }
}
}
}
該宏使用一個靜態變數,來決定調用是否繼續。我們的子函數HandleAsserting()可以關閉這個靜態變數,允許我們禁用這個位置以後的測試(例如,在一個迴圈中第一次失敗後)。子函數返回True執行彙編調用'int 3',在斷言後中斷到調試器。
三個選項
由於這些特色,HandleAsserting()調用有三個選項:
設定靜態標誌為0,阻止以後的測試,“解僱”斷言。
返回true,中斷到調試器。
返回false,繼續執行。
下面是一個簡單的non-VCL實現,在assert2.cpp檔案結尾有(被注釋掉的):
int HandleAsserting(char *testStr,char *msgStr,char *fileStr,int line,int *callFlag)
{
// assert message & and return flag regarding aborting:
// callFlag set if repeating forbidden
static char s_text[199]=""; // don't assign dynamically in
// case of 'out of memory' error
wsprintf(s_text,"FAILED: %srn"
"Error: ( %s )rn"
"File '%s', Line %drn"
"Abort execution, allow assert Retry, or Ignore in future?",
msgStr,testStr,fileStr,line);
switch ( ::MessageBox(NULL,s_text,"ASSERTION ERROR",MB_ABORTRETRYIGNORE) )
{
case IDIGNORE: // prevent calling again - turn off flag
*callFlag=0; // never call again
break;
case IDABORT: // return flag and break
return 1; // abort/break
}
return 0;
}
這個函數調用MessageBox()去顯示宣告失敗,使用Abort/Retry/Ignore按鈕來獲得三種可能情況。
鑒於這比較有用,我們讓C++ Builder 用我們的調用,當然,可以根據我們的需要定製VCL Form。本文提供的原始碼包含一個TRichEdit控制項,斷言錯誤資訊的格式很鮮明。示範程式允許您解僱斷言,實驗不同的選項。一個關於VCL版本的告誡是——在其他表單構造時避免用它。
結束
斷言是一種保證代碼按您期望的那樣做,不增加冗餘代碼的唾手可得的方式。本文提供了一些附加的你會發現比較有用的特色,擴充了使用斷言的機會。
(翻譯 01soft)