assert用法,原理,改编(C++)

转自: http://hi.baidu.com/hplonline/blog/item/8637ab4470ee268bb3b7dcaa.html

最近才发现,原来assert这么好用啊。。。
再看看是怎么实现的,又找到了些有趣的东西。

用法:

先包含
#inlcude <assert.h>

在想用的地方给一句:
assert(expression)就可以了。
expression是任意有效的逻辑表达式。
比如:

FILE *fp = fopen("in.txt","r") ;
if ( ! fp ){
    exit(0) ;
}
assert(fp != NULL) ;

当expression不满足时,就会报出一个很丑陋的框框,
然后向控制台输出assert不满足的文件和行号。

具体到debug的时候,
可以撒网式地在各个地方放上认为应该为真的表达式的assert,
说不定哪个就爆了,于是趁机发现了问题。

原理:

只要有源码就没有秘密,
所以打开assert.h,看看里面是怎么写的。

主要的就这两句:
_CRTIMP void __cdecl _assert(void *, void *, unsigned);
#define assert(exp) (void)( (exp) || (_assert(#exp, __FILE__, __LINE__), 0) )

第一句就干的就是输出一些信息,然后弹出个框框,
顺便结束程序这些勾当。
他被调用的时候,是类似于:
_assert("false" , "c:\\1.cpp" , 15)
这样。

第二句的构造可谓精简啊,小小一句话还包含了挺多以前没注意到的事情。

1.短路求值

这个是c的重要特性,在处理&&的时候前面为假则不用继续,
在处理|| 的时候,前面为真则不用继续。
形象地说把后面的表达式短路了。

2.单行宏

#exp 生成"exp"这样的字符串
#@a 生成'a'这样的字符
a##b 把a和b连接起来

第一个用法在这里见到了,第二个暂时还没见到用的实例。
第三个在a和b是宏的参数的时候有用。否则直接的ab会被当作一个东西。

3.特殊的预定义宏

__FILE__ 会被替换成所在的文件,字符串形式
__LINE__ 会被替换成行号,unsigned类型
__DATE__ 会被替换成日期
__TIME__ 会被替换成时间

其实之前翻过的跟C有关的书应该都讲了这些的。
不过拿着一个列表,又不给出真正实用的例子,
当然不知道这些东西是怎么回事,
久了自然也就忘了。

4.逗号表达式

感觉实在是一个用的很少的事情,
毕竟有多句话的时候,完全可以用分号就行了。
虽然有好多地方在if之类的里面很压缩的用逗号表达式写好几句话,
其实都可以改得不用逗号表达式的。

其一是逗号表达式的优先级很低,所以后面那对括号实在是不可缺少。

其二是逗号表达式的值为最右边式子的值。
这个估计很多人都记过,但不见得有啥重大意义。
这里,倒确实是发挥了他的意义。
因为_asert这个函数是void型的,
如果不使用逗号表达式在右边补个0的话,
会报告:(VC6)
error C2297: '||' : illegal, right operand has type 'void'

改编:

知道是怎么回事,当然可以很容易做出自己想要的东西。
再说还有asert.h里面的参照呢。

比如,我嫌默认的_assert弹出的东西看着太压抑了。。。
就自己写个就行了。

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX_BUFFER 200
void _assert(char *msg , char *file , unsigned line){
    char buf[MAX_BUFFER] ;
    sprintf(buf , "assertion fail:\n%s\nin file:\n%s\non line:\n%d" , msg , file , line) ;
    ::MessageBox(NULL , buf , "assertion failure" , MB_OK) ;
    exit(0) ;
}

#define assert(exp) ((exp) || (_assert(#exp , __FILE__ , __LINE__) , 0) )

int main(){
    assert(1 == 1 && 3 == 4) ;
    return 0 ;
}

效果:


至于我的这个是不是更压抑。。那不属于这里讨论的问题了。

反正通过简单变更_assert函数,可以把相关情况输出到文件,
或者选择另外的方式表达出来,能想到的都可以。

至于assert这个宏,也有可以动手脚的地方。
自带的是assert一个为真的表达式。
有的时候就想assert一个为假的表达式,当他为真的时候发出警告。

比如:

FILE *fp = fopen("in.txt","r") ;
if ( ! fp ){
    exit(0) ;
}
warn(fp == NULL)

套用上面的写法,既然是为真发警告,那么用&&去换||就行了。 
原文地址:https://www.cnblogs.com/nsnow/p/1739021.html