改进的C++ Builder assert()

类别:编程语言 点击:0 评论:0 推荐:

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)

 

 

本文地址:http://com.8s8s.com/it/it29309.htm