assert宏
assert的宏是一个表达式,如果该表达式为0,就让程序终止执行,并给出出错信息。
assert(x > y);
在x大于y时什么也不做,其他时候终止程序并且返回出错信息。
尝试定义assert宏
#define assert(e) if(!e) assert_error(_FILE_,_LINE_)
因为使用宏的时候会加上一个分号,所以在宏定义时没有加分号。
这里的
_FILE_
_LINE_
都是内建于C语言预编译器的宏,它们会被拓展为所在文件的文件名和所处代码行的行号。
下面是这种定义可能导致的难于察觉的错误
if(x > 0&&y > 0)
assert(x > y);
else
assert(y > x);
这个语句看起来好像是正确的,但是将宏定义替换过来时就会发现它的作用于我们期望的不一样:
if(x > 0&&y > 0)
if(!(x > y))
assert_error("文件名",代码行号);
else
if(!(y > x))
assert_error("文件名",代码行号);
也许将宏定义的表达式括起来就可以了:
#define assert(e) {if(!e) assert_error(_FILE_,_LINE_);}
但是将宏替换后:
if(x > 0&&y > 0)
{if(!(x > y)) assert_error("文件名",代码行号);};
else
{if(!(y > x)) assert_error("文件名",代码行号);};
else前面的分号会导致语法错误。
那我们可以调用assert时在后面都不用分号:
assert(x > y)
但是这样又太过于怪异。
一种可行的assert宏定义
#define assert(e) ((void)((e)||_assert_error(_FILE_,_LINE_)))
这个定义利用了||操作符对两侧的操作数依次求值的性质。
先判断e是否为真。如果e为真,那么就不用求右侧表达式的值;而如果e为假,那么就会去求右侧表达式的值,此时_assert_error将被调用,并打印出一条恰当的“断言失败”的出错信息。