在刚开始写代码的时候对于程序中检测程序有效性时是使用assert还是if我们总是会有一些困惑,在多数的malloc函数调用后要使用assert对指针进行检测,但是我们偶尔也会看到使用if的情况那到底是使用assert还是if呢?接下来我为大家简单的解释一下:
#ifdef NDEBUG//release模式下
#define assert(_Expression) ((void)0)
#else /* NDEBUG */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
_CRTIMP void __cdecl _wassert(_In_z_ const wchar_t * _Message, _In_z_ const wchar_t *_File, _In_ unsigned _Line);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )
#endif /* NDEBUG */
这是库里面对assert的定义,从函数可以看出在非debug模式下(就是release模式)assert是不起任何作用的,在debug模式下如果表达式的值是0,那么输出消息并终止程序的运行,如果表达式的结果为真那么assert不做任何操作,所以说如果assert断言失败就表示程序中存在bug,出现了预期不应该存在的情况。
assert是用来发现运行时错误的捕捉在运行时发生不应该发生的非法情况,发现的错误是关于程序实现方面的,使用断言的最根本好处是可以发现许多程序运行时错误而且是可以在错误产生的发源地发现错误,有助于程序员及时发现并作出修改。
assert一般是用来检测函数参数的合法性即有效性并不是是否正确,但合法的程序并不一定是正确的,函数参数为NULL或者使用了未初始化的参数都会导致程序不能正确的运行。
切记不要混淆了非法情况和错误情况,前者是程序员不希望看到的会导致程序不能按照所希望的情况那样运行下去,后者是程序运行时自然存在的并且一定要对其进行处理的。
eg1:
bool FunTest(int *p)
{
assert(p);
//do something
上面那个例子到底要用assert还是if呢?
指针并不是在任何情况下都需要对其进行判断是否为空,比如指向链表的第一个有效节点的指针,如果链表中一个有效节点都没有那么指针就指向NULL,此时就不能使用assert来断言。但是当你确定你的指针不能出现指向NULL的情况,如果出现了就是错误那么你可以使用assert来进行断言,方便我们进行定位排查问题,而此时你如果使用了if那么程序有可能会继续执行下去,不会把错误抛出,那么如果以后程序因为此处的bug发生错误停止之后,此处bug很可能隐藏的很深,那么我们的排查可是相当困难的。
eg2:
void FunTEst()
{
int *q = (int *)malloc(sizeof(int));
assert(q);//错误
//do something
}
此处assert使用错误,因为内存分配失败属于合法情况,如果内存分配失败此时*p==NULL;那么此时使用assert断言会是程序中断,建议使用if。
总计:
(1)assert是调试宏不是函数,只有在debug模式下起作用
(2)使用assert来判断程序运行中出现的非法情况,在你的程序中如果某种情况一定不会出现那么建议使用assert断言