#include <assert.h>
void assert( int expression );
assert的作用是现计算表达式 expression ,假设其值为假(即为0),那么它先向stderr打印一条出错信息,
然后通过调用 abort 来终止程序执行。
提高程序健壮性之assert使用
编写能正常执行的程序非常难;编写在错误情况下仍然表现的非常“优雅”的程序更难。这篇文章将和大家讨论一些编程技巧,能够使我们在执行中的程序中早点发现错误,检測和从问题中恢复。那就先讨论下断言(assert)的使用吧。
在编码时,有一个好的目标应该时刻铭记在心,那就是:应该想办法让bug或者异常错误尽早使得程序down掉,或者出现错误。由于这样能够帮助你在开发和測试阶段尽快找出bug。有一些错误不会无缘无故的暴露自己,往往是产品都到了客户手上,这些错误才会显现出来。
一个最简单的检查异常条件的方法是使用标准C的assert宏,它的參数是一个bool表达式。当表达式为假时,程序会退出。在退出之前打印错误消息,包含源文件,行号,和表达式本身。断言很实用,它提供了一个作用于程序内部的广泛的一致性检查方法。比如,使用断言測试函数參数的有效性,測试异常的返回值等等。
每个断言的使用不仅提供了一个程序执行时的条件检查,也像一个对源码级别的程序操作的说明性文档。假设你的程序包括了一个断言,也就是告诉那些阅读你源码的人,在你的源码中,在程序的这一点,这个条件应该为真,假设不为真,那就是一个bug。
当然,在追求性能的代码中,使用assert会减少程序性能。可是你放心,在编译时增加NDEBUG參数编译器就能够对assert进行预处理,从而移除它。正由于在预处理时可能移除assert,那你使用时就得小心了。什么时候用,什么时候不用就成了一个问题。通常,你不应该在assert内部调用函数,定义变量,或者使用改变值的操作符,如++。
我们如果你这样使用了:
for (i = 0; i <= 100; ++i) assert (do_something () == 0);
然后,你可能会发现这样会使得性能大大减少,从而在创新编译使使用NDEGUG參数。这将移除整个assert宏,这就将do_something( )也被移除了,再也不被调用。为了纠正错误,你应该这样写:
for (i = 0; i <= 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);,这将帮助你检測函数的错误使用,这也给源码阅读者非常清晰的印象,那就是在这里对函数的參数值有限制。
说了这么多,行动起来吧,大胆的在你的程序中使用断言。