zoukankan      html  css  js  c++  java
  • c++ assert() 使用方法

    assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:
    #include <assert.h>
    void assert( int expression );

    assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,
    然后通过调用 abort 来终止程序运行。

    请看下面的程序清单badptr.c
    #include <stdio.h>
    #include <assert.h>
    #include <stdlib.h>

    int main( void )
    {
           FILE *fp;
        
           fp = fopen( "test.txt", "w" );//以可写的方式打开一个文件,如果不存在就创建一个同名文件
           assert( fp );                           //所以这里不会出错
           fclose( fp );
        
           fp = fopen( "noexitfile.txt", "r" );//以只读的方式打开一个文件,如果不存在就打开文件失败
           assert( fp );                           //所以这里出错
           fclose( fp );                           //程序永远都执行不到这里来

           return 0;
    }

    [root@localhost error_process]# gcc badptr.c 
    [root@localhost error_process]# ./a.out 
    a.out: badptr.c:14: main: Assertion `fp'' failed.
    已放弃

    使用assert的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销。
    在调试结束后,可以通过在包含#include <assert.h>的语句之前插入 #define NDEBUG 来禁用assert调用,示例代码如下:
    #include <stdio.h>
    #define NDEBUG
    #include <assert.h>

    用法总结与注意事项:
    1)在函数开始处检验传入参数的合法性
    :

    int resetBufferSize(int nNewSize)
    {
    //功能:改变缓冲区大小,
    //参数:nNewSize 缓冲区新长度
    //返回值:缓冲区当前长度 
    //说明:保持原信息内容不变     nNewSize<=0表示清除缓冲区
    assert(nNewSize >= 0);
    assert(nNewSize <= MAX_BUFFER_SIZE);

    ...
    }

    2)每个assert只检验一个条件,因为同时检验多个条件时,如果断言失败,无法直观的判断是哪个条件失败

    不好: assert(nOffset>=0 && nOffset+nSize<=m_nInfomationSize);

    : assert(nOffset >= 0);
    assert(nOffset+nSize <= m_nInfomationSize);


    3)不能使用改变环境的语句,因为assert只在DEBUG个生效,如果这么做,会使用程序在真正运行时遇到问题
    错误: assert(i++ < 100)
    这是因为如果出错,比如在执行之前i=100,那么这条语句就不会执行,那么i++这条命令就没有执行。
    正确: assert(i < 100)
             i++;
                
          
    4)assert和后面的语句应空一行,以形成逻辑和视觉上的一致感

    5)有的地方,assert不能代替条件过滤

    文章出处:http://www.diybl.com/course/3_program/c++/cppjs/20071111/85534.html

    摘自《高质量C/C++编程指南》Page 41-42...

    程序一般分为Debug 版本和Release 版本,Debug 版本用于内部调试,Release 版本发行给用户使用。
    断言assert 是仅在Debug 版本起作用的宏,它用于检查不应该发生的情况。示例6-5 是一个内存复制函数。在运行过程中,如果assert 的参数为假,那么程序就会中止(一般地还会出现提示对话,说明在什么地方引发了assert)。

    void *memcpy(void *pvTo, const void *pvFrom, size_t size)
    {
        assert((pvTo != NULL) && (pvFrom != NULL)); // 使用断言
        byte *pbTo = (byte *) pvTo; // 防止改变pvTo 的地址
        byte *pbFrom = (byte *) pvFrom; // 防止改变pvFrom 的地址
        while(size -- > 0)
            *pbTo ++ = *pbFrom ++ ;
        return pvTo;
    }
    示例6-5 复制不重叠的内存块

    assert 不是一个仓促拼凑起来的宏。为了不在程序的Debug 版本和Release 版本引起差别,assert 不应该产生任何副作用。所以assert 不是函数,而是宏。程序员可以把assert看成一个在任何系统状态下都可以安全使用的无害测试手段。如果程序在 assert 处终止了,并不是说含有该assert 的函数有错误,而是调用者出了差错,assert 可以帮助我们找到发生错误的原因。

    很少有比跟踪到程序的断言,却不知道该断言的作用更让人沮丧的事了。你化了很多时间,不是为了排除错误,而只是为了弄清楚这个错误到底是什么。有的时候,程序员偶尔还会设计出有错误的断言。所以如果搞不清楚断言检查的是什么,就很难判断错误是出现在程序中,还是出现在断言中。幸运的是这个问题很好解决,只要加上清晰的注释即可。这本是显而易见的事情,可是很少有程序员这样做。这好比一个人在森林里,看到树上钉着一块危险的大牌子。但危险到底是什么?树要倒?有废井?有野兽?除非告诉人们危险是什么,否则这个警告牌难以起到积极有效的作用。难以理解的断言常常被程序员忽略,甚至被删除。

    【规则6-5-1】使用断言捕捉不应该发生的非法情况。不要混淆非法情况与错误情况之间的区别,后者是必然存在的并且是一定要作出处理的。
    【规则6-5-2】在函数的入口处,使用断言检查参数的有效性(合法性)。
    【建议6-5-1】在编写函数时,要进行反复的考查,并且自问:我打算做哪些假定?一旦确定了的假定,就要使用断言对假定进行检查。
    【建议6-5-2】一般教科书都鼓励程序员们进行防错设计,但要记住这种编程风格可能会隐瞒错误。当进行防错设计时,如果不可能发生的事情的确发生了,则要使用断言进行报警。

    ASSERT宏中应该包含的元素:

    判断条件;输出当前断言失败的位置(文件、行数等);返回错误;终止程序...

    几种典型的ASSERT的写法:

    VC中的写法:

    #define ASSERT(f) 
    do 

       if (!(f) && AfxAssertFailedLine(THIS_FILE, __LINE__)) 
       AfxDebugBreak(); 
    } while (0) 

    #define _ASSERT(expr) 
            do { if (!(expr) && 
                    (1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, NULL, NULL))) 
                 _CrtDbgBreak(); } while (0)

    其他平台的写法:

    # define ASSERT(x) ((x) || (dbg_printf("assertion failed ("__FILE__":%d): "%s" ",__LINE__,#x), break_point(), FALSE))

    原网站地址:http://hi.baidu.com/uwbadnhctpkopwr/item/1d5d1e1d316c79fcdceeca0a

  • 相关阅读:
    转载完美解决国内访问GitHub速度太慢的难题
    leetcodedp最长子序列问题isSubsequence
    三级域名
    2021年终总结
    leetcodedp背包子集问题
    dp01背包
    springboot整合mybatis(使用的baomidou的mybatisplusbootstarter)实现多数据源切换
    leetcode完全背包518.零钱兑换II
    mybatislogplugin
    Mybatis log plugin插件破解修复版 MyBatis Log Plugin License Authorization Failed
  • 原文地址:https://www.cnblogs.com/feifanrensheng/p/7880519.html
Copyright © 2011-2022 走看看