zoukankan      html  css  js  c++  java
  • 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)

    套用上面的写法,既然是为真发警告,那么用&&去换||就行了。 
  • 相关阅读:
    ASP.NET Core 2.1 Web API + Identity Server 4 + Angular 6 + Angular Material 实战小项目视频
    .NET Core TDD 前传: 编写易于测试的代码 -- 单一职责
    学习Identity Server 4的预备知识 (误删, 重补)
    .NET Core TDD 前传: 编写易于测试的代码 -- 全局状态
    .NET Core TDD 前传: 编写易于测试的代码 -- 依赖项
    .NET Core TDD 前传: 编写易于测试的代码 -- 构建对象
    .NET Core TDD 前传: 编写易于测试的代码 -- 缝
    SpringBoot入门教程(十)应用监控Actuator
    SpringBoot入门教程(九)定时任务Schedule
    SpringBoot入门教程(八)配置logback日志
  • 原文地址:https://www.cnblogs.com/nsnow/p/1739021.html
Copyright © 2011-2022 走看看