assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:
#include <assert.h>
void assert( int expression );
使用场景
对来自系统内部的可靠的数据使用断言,对于外部不可靠数据不能够使用断言,而应该使用错误处理代码
即断言是用来处理不应该发生的非法情况,而对于可能会发生且必须处理的情况应该使用错误处理代码,而不是断言。
原则
断言内的条件是无条件为true的,如果断言失败,意味着程序逻辑错误,即程序存在bug,应当被修复;
断言只在debug模式下使用,在release模式,应当屏蔽掉断言,以避免对运行速度和binary文件的大小的影响;
断言不应该用来作为输入的合法性检查,也不应该用于异常处理,只作为debug目的,并且assert检查失败的情况按照正常情况应该永远不会出现;
适用范围:
assert 只有在 Debug 版本中才有效,如果编译为 Release 版本则被忽略。
#define NDEBUG // 禁用断言
eg:
char * Strdup(const char * source)
{
assert(source != NULL); // 正确使用assert,用来检查该程序正常工作时绝对不应该发生的非法情况
char * result=NULL;
size_t len = strlen(source) +1;
result = (char *)malloc(len);
assert(result != NULL); // 错误使用assert,它测试的是错误情况,对 malloc 函数而言,当内存不足导致内存分配失败时就会返回 NULL,
// 因此这里不应该使用 assert 宏进行处理,而应该使用错误处理代码,使用 if (result != NULL) {}
strcpy(result, source);
return result;
}
注意:
1.尽量在函数中使用断言来检查参数的合法性
2.避免在断言表达式中使用改变变量的语句
3.避免使用断言去检查程序错误
4.尽量在防错性程序设计中使用断言来进行错误报警
5.用断言保证没有定义的特性或功能不被使用
6.谨慎使用断言对程序开发环境中的假设进行检查
7.每个assert只检验一个条件,因为同时检验多个条件时,如果断言失败,无法直观的判断是哪个条件失败
8.assert和后面的语句应空一行,以形成逻辑和视觉上的一致感。
补充:
4.1 主动式防错程序设计是指周期性地对整个程序或数据库进行搜查或在空闲时搜查异常情况。它既可以在处理输入信息期间使用,也可以在系统空闲时间或等待下一个输入时使用。如下面所列出的检查均适合主动式防错程序设计。
内存检查:如果在内存的某些块中存放了一些具有某种类型和范围的数据,则可对它们做经常性检查。
标志检查:如果系统的状态是由某些标志指示的,可对这些标志做单独检查。
反向检查:对于一些从一种代码翻译成另一种代码或从一种系统翻译成另一种系统的数据或变量值,可以采用反向检查,即利用反向翻译来检查原始值的翻译是否正确。
状态检查:对于某些具有多个操作状态的复杂系统,若用某些特定的存储值来表示这些状态,则可通过单独检查存储值来验证系统的操作状态。
连接检查:当使用链表结构时,可检查链表的连接情况。
时间检查:如果已知道完成某项计算所需的最长时间,则可用定时器来监视这个时间。
其他检查:程序设计人员可经常仔细地对所使用的数据结构、操作序列和定时以及程序的功能加以考虑,从中得到要进行哪些检查的启发。
4.2 被动式防错程序设计则是指必须等到某个输入之后才能进行检查,也就是达到检查点时才能对程序的某些部分进行检查。一般所要进行的检查项目如下:
来自外部设备的输入数据,包括范围、属性是否正确。
由其他程序所提供的数据是否正确。
数据库中的数据,包括数组、文件、结构、记录是否正确。
操作员的输入,包括输入的性质、顺序是否正确。
栈的深度是否正确。
数组界限是否正确。
表达式中是否出现零分母情况。
正在运行的程序版本是否是所期望的(包括最后系统重新组合的日期)。
通过其他程序或外部设备的输出数据是否正确。