assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,我们常常这样使用assert宏:
- void main()
- {
- int* p = NULL;
- p = (int *)malloc(sizeof(int));
- assert(p != NULL);
- ...
- }
如果让我来定义assert宏,我可能会定义成如下的形式:
- #define assert(exp) if(!exp) _assert(#exp, __FILE__, __LINE__)
上面的宏使用的是语句,在某些情形下,这个宏有一些难以察觉的错误,假如我们有如下的宏调用:
- if(x > 0)
- assert(y > x);
- else
- assert(x > y);
- ...
我们把宏展开:
- if(x > 0)
- if(!(y > x))) _assert("y > x", __FILE__, __LINE__);
- else
- if(!(x > y)) _assert(" x > y", __FILE__, __LINE__);
- ...
由于else默认是跟离它最近的if匹配,我们重新缩进下:
- if(x > 0)
- if(!(y > x))) _assert("y > x", __FILE__, __LINE__);
- else
- if(!(x > y)) _assert(" x > y", __FILE__, __LINE__);
- ...
这和我们想要的结果是不同的,
我们再来看看系统如何定义assert宏:
- #define assert(exp) (void)((exp) || (_assert(#exp, __FILE__, __LINE__), 0))
这个宏是一个表达式,不是语句,利用了||语句的短路现象,||前面的表达式为真时,后面的不再计算,当||之前为假时,才处理后面的表达式;
宏中有个#exp,这里的#号是提取exp的值;
表达式最后有一个0处于逗号运算符之后,这样处理确保整个表达式最后值为0,即为false。
|