请看下面的程序清单badptr.c:php
#includeexpress
#include编程
#includeapp
int main( void )函数
{性能
FILE *fp;测试
fp = fopen( "test.txt", "w" );//以可写的方式打开一个文件,若是不存在就建立一个同名文件ui
assert( fp ); //因此这里不会出错this
fclose( fp );编码
fp = fopen( "noexitfile.txt", "r" );//以只读的方式打开一个文件,若是不存在就打开文件失败
assert( fp ); //因此这里出错
fclose( fp ); //程序永远都执行不到这里来
return 0;
}
[root@localhost error_process]# gcc badptr.c
[root@localhost error_process]# ./a.out
a.out: badptr.c:14: main: Assertion `fp' failed.
已放弃
使用assert的缺点是,频繁的调用会极大的影响程序的性能,增长额外的开销。
在调试结束后,能够经过在包含#include的语句以前插入 #define NDEBUG 来禁用assert调用,示例代码以下:
#include
#define NDEBUG
#include
用法总结与注意事项:
1)在函数开始处检验传入参数的合法性
如:
int resetBufferSize(int nNewSize)
{
//功能:改变缓冲区大小,
//参数:nNewSize 缓冲区新长度
//返回值:缓冲区当前长度
//说明:保持原信息内容不变 nNewSize<=0表示清除缓冲区
assert(nNewSize >= 0);
assert(nNewSize <= MAX_BUFFER_SIZE);
...
}
2)每一个assert只检验一个条件,由于同时检验多个条件时,若是断言失败,没法直观的判断是哪一个条件失败
很差: assert(nOffset>=0 && nOffset+nSize<=m_nInfomationSize);
好: assert(nOffset >= 0);
assert(nOffset+nSize <= m_nInfomationSize);
3)不能使用改变环境的语句,由于assert只在DEBUG个生效,若是这么作,会使用程序在真正运行时遇到问题
错误: assert(i++ < 100)
这是由于若是出错,好比在执行以前i=100,那么这条语句就不会执行,那么i++这条命令就没有执行。
正确: assert(i < 100)
i++;
4)assert和后面的语句应空一行,以造成逻辑和视觉上的一致感
5)有的地方,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);,这将帮助你检测函数的错误使用,这也给源代码阅读者很清晰的印象,那就是在这里对函数的参数值有限制。
说了这么多,行动起来吧,大胆的在你的程序中使用断言。