断言的使用

Posted on 2010-01-17 19:36 rikisand 阅读(598) 评论(0)  编辑 收藏 引用 所属分类: 工作记录~~everydayC/C++Windows ~

解决项目的问题,意识到断言的重要性。如果一个程序在某处遇到了非法的值,那么最好的情况便是在此刻停下报错,最坏的情况便是程序不吭不响的执行着~~直到你发现他执行的方式极为诡异,此时,你要花九牛二虎之力才能找到错误所在之处~~~~

学习一下断言吧:

·······什么是断言

在某处判断某一个表达式的值为真或者假,如果假则输出错误消息并停止程序的执行~

assert是宏,而不是函数,只在debug版本中有效,因此无需在release版本删除。

·······哪几种断言

MFC

ASSERT

void foo(char* p,int size)
{
ASSERT(p != 0); // 验证缓冲区指针
ASSERT((size >= 100); // 确认缓冲区大小至少为100字节
// foo 函数的其它计算过程
}
如果没有定义_DEBUG预处理符,则该语句不会真正生成代码。Visual C++会在调试模式编译时自动定义_DEBUG,而在发行模式下,该预处理符是不存在的。如果定义了_DEBUG,则上述两个断言生成的代码类如:
//ASSERT(p != 0);
do
{
if(!(p != 0) && AfxAssertFailedLine(__FILE__, __LINE__))
AfxDebugBreak();
} while(0);
//ASSERT((size >= 100);
do
{
if(!(size >= 100) && AfxAssertFailedLine(__FILE__,__LINE__))
AfxDebugBreak();
}while(0);

ASSERT_KINDOF(classname,pObject); ASSERT_KINDOF(CDocument,pDocument);

检验pObject指向的对象是classname类的一个对象或者其派生类的对象

ASSERT_VALID(pObject); pObject 必须是一个派生于CObject类的类对象,会调用其重写的AssertValid函数 ,例如

如果使用应用向导或类向导生成基于MFC的类,通常会得到AssertValid()的骨架,最好改写这些骨架代码以增加最基本的完整性检查。下面是一个典型的例子,类Sample从CObject继承,假定它含有职员名字及其薪水:
class Sample : public CObject
{
    protected:
    CString m_Name; // 职员名字
    double m_Salary; // 薪水
public:
    Sample(LPCTSTR name,double salary) : m_Name(name), m_Salary(salary) {}
   #ifdef _DEBUG
        virtual void AssertValid() const;
    #endif

};
#ifdef _DEBUG
void Sample::AssertValid() const
{
    CObject::AssertValid(); // 验证基类
    ASSERT(!m_Name.IsEmpty()); // 验证职员名字
    ASSERT(m_Salary > 0); // 验证薪水
}
#endif

CRT assertion

_ASSERT 和  _ASSERTE 后一个会在出错时同时打印出条件判断句

ANSI

assert()

注意:assert用于检测非法的输入,但是合法的输入并不一定是正确的,例如:

int pB = (int*)malloc(sizeof(int)*1000);

assert(pB!=NULL) //错误的使用assert 他会在release版本失效~也就是说assert不应该对程序产生副作用

正确的做法:

int pB = (int*) malloc(sizeof(int)*1000);

if(pB == NULL)

{
   //错误处理

}

else{

}

另一个例子:

void draw(){

   CFigure* pF = getCF();

   assert(pf!=NULL);

   if(pf == NULL){}

   else{

   }

}

此处,对于getCF来说返回值为NULL是非法的,如果他的返回值可能为null就没必要加上assert语句。

而下面的if语句则是为了防止release版本出现null指针的情况。

 

 

VERIFY()

由于ASSERT仅在程序的调试版起作用,测试表达式总是被动的。也就是说,它们不能包含赋值、增量、减量等真正改变数据的操作。但有时候我们需要验证一个主动表达式,比如赋值语句。这时可以使用VERIFY代替ASSERT。下面是一个例子:
void foo(char* p,int size)
{
char* q; // 指针的副本
VERIFY(q = p); // 拷贝指针并执行验证
ASSERT((size >= 100); // 确保缓冲区大小至少为100字节
// 执行 foo 的其它操作
}
在调试模式下ASSERT和VERIFY是相同的。但在release模式下,VERIFY能够继续对表达式求值(但不再进行断言检验),而ASSERT语句在效果上就如同已经删除了一样。
尽管在MFC源代码中可以找到一些应用VERIFY的例子,但ASSERT用得更为普遍。一些程序员总是完全避免使用VERIFY,因为他们已经习惯于使用被动断言。请记住,如果在ASSERT语句中使用了主动表达式,编译器不会发出任何警告。在发行模式下编译时该表达式会被直接删除,从而导致程序运行的错误。由于发行版程序不含调试信息,这种类型的错误是很难找到原因的。

 

 

 

 

 

 

 

 

 

 

 

 


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理