zoukankan      html  css  js  c++  java
  • ASSERT断言

    ASSERT断言

      编写代码时,我们总是会做出一些假设,断言就是用于在代码中捕捉这些假设,可以将断言看作是异常处理的一种高级形式。断言表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真。可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言,而在部署时禁用断言。同样,程序投入运行后,最终用户在遇到问题时可以重新起用断言。

      代码执行之前必须具备的特性;

      assert是宏,而不是函数;
      使用断言可以创建更稳定,品质更好且不易于出错的代码。
      断言语句不是永远会执行,可以屏蔽也可以启用。
      
    1. 断言使用条件
      (1)使用断言测试方法执行的前置条件和后置条件;
      (2)可以在预计正常情况下程序不会到达的地方放置断言 :assert false
    2. C语言中
      宏名: assert
      功 能: 测试一个条件并可能使程序终止
      用 法: void assert(int test);
    #include<assert.h>
    #include<stdio.h>
    #include<stdlib.h>
    struct ITEM
    {
        int key;
        int value;
    };
    /*add item to list,make sure list is not null*/
    void additem(struct ITEM* itemptr)
    {
        assert(itemptr!=NULL);
        /*additemtolist*/
    }
    int main(void)
    {
        additem(NULL);
        return 0;
    }

      assert() 宏用法

      注意:assert是宏,而不是函数。在C的assert.h头文件中

      assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义

    #defineassert(expr)
    ((expr)
    ?__ASSERT_VOID_CAST(0)
    :__assert_fail(__STRING(expr),__FILE__,__LINE__,__ASSERT_FUNCTION))
     
    /*DefinedInGlibc2.15*/

      assert的作用是先计算表达式expr, 如果其值为假(即为0),那么它会打印出来assert的内容和__FILE__, __LINE__, __ASSERT_FUNCTION,然后执行abort()函数使kernel杀掉自己并coredump(是否生成coredump文件,取决于系统 配置);否则,assert()无任何作用。宏assert()一般用于确认程序的正常操作,其中表达式构造无错时才为真值。完成调试后,不必从源代码中 删除assert()语句,因为宏NDEBUG有定义时,宏assert()的定义为空。

    #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;
    }

      在调试结束后,可以通过在包含#include <assert.h>的语句之前插入

      #define NDEBUG //来禁用assert调用

    #include <stdio.h>
    #define NDEBUG
    #include <assert.h>

    3. 用法总结与注意事项

      (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不能代替条件过滤

    注意:当对于浮点数:
    #include<assert.h>
    float pi=3.14f;
    assert (pi==3.14f);
    在switch语句中总是要有default子句来显示信息(Assert)。
    int number = SomeMethod();
    switch(number){
    case 1: Trace.WriteLine("Case 1:");
    break;
    case 2: Trace.WriteLine("Case 2:");
    break;
    default : Debug.Assert(false);
    break;
    }

     4. C++中的用法

       void assert(  int expression ); 

      参数:Expression (including pointers) that evaluates to nonzero or 0.(表达式【包括指针】是非零或零)
      原理:assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行

     1 // crt_assert.c  
     2 // compile with: /c  
     3 #include <stdio.h>  
     4 #include <assert.h>  
     5 #include <string.h>  
     6   
     7 void analyze_string( char *string );   // Prototype  
     8   
     9 int main( void )  
    10 {  
    11    char  test1[] = "abc", *test2 = NULL, test3[] = "";  
    12   
    13    printf ( "Analyzing string '%s'
    ", test1 ); fflush( stdout );  
    14    analyze_string( test1 );  
    15    printf ( "Analyzing string '%s'
    ", test2 ); fflush( stdout );  
    16    analyze_string( test2 );  
    17    printf ( "Analyzing string '%s'
    ", test3 ); fflush( stdout );  
    18    analyze_string( test3 );  
    19 }  
    20   
    21 // Tests a string to see if it is NULL,   
    22 // empty, or longer than 0 characters.  
    23 void analyze_string( char * string )  
    24 {  
    25    assert( string != NULL );        // Cannot be NULL  
    26    assert( *string != '' );       // Cannot be empty  
    27    assert( strlen( string ) > 2 );  // Length must exceed 2  
    28 } 

      输出:

        Analyzing string 'abc'  
        Analyzing string '(null)'  
        Assertion failed: string != NULL, file assert.cpp, line 25  
    abnormal program termination

      加入#define NDEBUG之后,上文第一个例子输出结果为:

    #include <stdio.h>
    #define NDEBUG
    #include <assert.h>

      添加 #define NDEBUG后输出如下:

        Analyzing string 'abc'  
        Analyzing string '(null)'  
        Analyzing string ''  

    5. C++例子

      在面试中经常用到的一个题目:
      已知memcpy的函数为:

      void* memcpy(void *dest , const void* src , size_t count)

      其中dest是目的指针,src是源指针。不调用c++/c的memcpy库函数,请编写memcpy。

        void* memcpy(void *dst, const void *src, size_t count)      
        {      
            //安全检查  
            assert( (dst != NULL) && (src != NULL) );      
          
            unsigned char *pdst = (unsigned char *)dst;      
            const unsigned char *psrc = (const unsigned char *)src;      
          
            //防止内存重复  
            assert(!(psrc<=pdst && pdst<psrc+count));      
            assert(!(pdst<=psrc && psrc<pdst+count));      
          
            while(count--)      
            {      
                *pdst = *psrc;      
                pdst++;      
                psrc++;      
            }      
            return dst;      
        }    
  • 相关阅读:
    Linux 禁用ipv6
    【搬运】Get Log Output in JSON,通过Log4j2与Logback输出JSON格式日志
    Gnome禁用tracker-miner-apps、tracker-miner-fs、tracker-store
    Sentry错误日志监控你会用了吗?
    django执行源生的mysql语句
    django实现自定义manage命令的扩展
    C++教程详解
    python数据分析教程大全
    将mysql主键id从1开始 变为自增
    django restful framework教程大全
  • 原文地址:https://www.cnblogs.com/icmzn/p/5057181.html
Copyright © 2011-2022 走看看