2019年4月18日 关于使用断言assert的简易说明(一)

断言就是对某种假设条件进行检查。
在 C 语言中,断言被定义为宏的形式(assert(expression)),而不是函数,其原型定义在<assert.h>文件中。其中,assert 将通过检查表达式 expression 的值来决定是否需要终止执行程序。也就是说,如果表达式 expression 的值为假(即为 0),那么它将首先向标准错误流 stderr 打印一条出错信息,然后再通过调用 abort 函数终止程序运行;否则,assert 无任何作用。

默认情况下,assert 宏只有在 Debug 版本(内部调试版本)中才能够起作用,而在 Release 版本(发行版本)中将被忽略。当然,也可以通过定义宏或设置编译器参数等形式来在任何时候启用或者禁用断言检查(不建议这么做)。同样,在程序投入运行后,最终用户在遇到问题时也可以重新起用断言。这样可以快速发现并定位软件问题,同时对系统错误进行自动报警。对于在系统中隐藏很深,用其他手段极难发现的问题也可以通过断言进行定位,从而缩短软件问题定位时间,提高系统的可测性。

/尽量利用断言来提高代码的可测试性/
void swap(int *a, int *b)
{
assert(a != NULL&&b != NULL);//断言
//if (a == NULL || b == NULL) return;
int temp = *a;
*a = *b;
*b = temp;
}
(1)当然//if (a == NULL || b == NULL) return;也可以。但是随着函数参数或需要检查的表达式不断增多,这种检查测试代码将占据整个函数的大部分。这样代码看起来非常不简洁,而且也降低了函数的执行效率。
(2)或者说通过条件编译“#ifdef DEBUG”来同时维护同一程序的两个版本(内部调试版本与发行版本),即在程序编写过程中,编译其内部调试版本,利用其提供的测试检查代码为程序自动查错。而在程序编完之后,再编译成发行版本。
例如:
#ifdef DEBUG
if(a== NULL)
{
fprintf(stderr,“a is NULL\n”);
abort();
}
if(b == NULL)
{
fprintf(stderr,“b is NULL\n”);
abort();
}
#endif

上面的解决方案尽管通过条件编译“#ifdef DEBUG”能产生很好的结果,也完全符合我们的程序设计要求,但是仔细观察会发现,这样的测试检查代码显得并不那么友好,当一个函数里这种条件编译语句很多时,代码会显得有些浮肿,甚至有些糟糕。
因此,对于上面的这种情况,多数程序员都会选择将所有的调试代码隐藏在断言 assert 宏中。其实,assert 宏也只不过是使用条件编译“#ifdef”对部分代码进行替换,利用 assert 宏,将会使代码变得更加简洁。
例如:assert(a != NULL&&b != NULL);//断言。既完成程序的测试检查功能(即只要在调用该函数的时候为 a与b 参数错误传入 NULL 指针时都会引发 assert),与此同时,对 swap 函数的代码量也进行了大幅度瘦身,不得不说这是一个两全其美的好办法。

猜你喜欢

转载自blog.csdn.net/weixin_43949535/article/details/89377101