zoukankan      html  css  js  c++  java
  • 【C++】C++中assert和ENDEGU预处理语句

    assert

    断言语句是C++中的一种预处理宏语句,它能在程序运行时根据否定条件中断程序。

    C++中的assert()函数可以实现断言功能,在使用assert函数之前应该先引入<cassert>头文件。
    函数:

    void assert (int expression);

    如果参数表达式不为0(也就是true),那么什么都不会发生。参数表达式为0(也就是false),那么将会有一条标准的错误消息被打印,随后调用abort中断运行程序。

    打印的错误消息内容依据不同的实现库会有不同的消息内容。但消息内容至少应该包括:断言失败的表达式,文件的名称,断言失败处在文件中的行数。

    比如:

    #include <array> /*array*/
    #include <assert> /*assert()*/
    using namespace std;
    int getArrayValue(const std::array<int, 10> &array, int index)
    {
        // 断言index的范围是[0,9]
        assert(index >= 0 && index <= 9); // 这个是test.cpp的第7行
        return array[index];
    }
    int main(int argc,char **argv){
      array<int,10> array = {1,2,3,4,5,6,7,8,9,10};
      getArrayValue(array,-3);//调用getArrayValue函数,传入一个错误的index值
    return 0;
    }

    会得到如下的报错信息:

    test.cpp:7: int getArrayValue(std::array<int, 10ul>, int): Assertion `index >=0 && index <=9' failed.

    如何给断言语句添加额外的描述信息
    有时断言语句的描述信息不够清晰,比如考虑如下这种情况:

    assert(found);

    如果这个断言被触发,那么会得到类似于如下的错误信息:

    file_name:line_number : function_name: Assertion 'found' failed.

    这种情况,如果只看断言输出是得不到详细的信息,必需要去查看代码才能确定是什么原因导致了错误。

    那么有没有什么方式可以为断言添加一些额外的描述信息呢?答案是有的。我们可以利用C++中的&&符,添加一个字符串字面值的描述信息。

    assert(found && "Car could not found in database"); 

    由于字符串字面值总是为true,所以整个表达式的真假性还是取决于found变量。这样的话,既添加了额外的描述信息,又不改变原来的含义。
    如果断言触发,会得到如下的结果:

    file_name:line_number : function_name: Assertion 'found && "Car could not found in database"' failed.

    从断言输出的错误信息中,可以看到详细的错误描述。

    static_assert

    在c++11标准中添加了一种静态断言static_assert,和assert不同的是:assert表达式的检查在运行时发生,static_assert的检查在编译时发生。

    如果static_assert断言被触发的话,那么会在控制台打印错误信息,同时编译失败。若static_assert断言未被触发,那么编译顺利通过。
    比如:

    static_assert(sizeof(long) == 8, "long must be 8 bytes");
    int main(){return 0;}

    如果编译机器long类型不占8个字节的话,那么在编译的时候就会出现如下的错误信息:

    static assertion failed: long must be 8 bytes


    因为static_assert对条件式的检查发生在编译时,所以条件表达式一定要能在编译时被计算出来。在c++11中,static_assert的第二个参数是必需提供的,到c++17,第二个参数是可选的。

    EDEBUG

    在上面介绍了assert断言语句,其实assert的行为依赖一个名为NDEBUG的预处理变量的状态,如果定义了ENDEBUG,则assert什么也不会发生。默认状态下没有定义NDEBUG,assert会执行运行时检查。
    例如:

    #define NDEBUG
    #include <assert> /*assert()*/
    int getArrayValue(const std::array<int, 10> &array, int index)
    {
        // 断言index的范围是[0,9]
        assert(index >= 0 && index <= 9); // 这个是test.cpp的第7行
        return array[index];
    }

    注意#define NDEBUG必须要写在#include <assert>语句之前。

    定义NDEBUG能避免检查各种条件所需的运行时开销,当然此时根本就不会执行运行时检查。除了使用assert外,也可以使用NDEBUG编写自己的条件调试代码。如果NDEBUG未定义,将执行#ifndef和#endif之间的代码;如果定义了NDEBUG,这些代码将会被忽略掉:

    void print(const int ia[],size_t size){
    #ifndef NDEBUG
        cerr << __func__ << ": array size is" << size << endl;
    #endif
    //...
    }

    上面这段代码中,我们使用变量__func__输出当前调试函数的名字。编译器为每个函数都定义了__func__,它是const char的静态数组,用于存放函数的名称。

    C++编译器除了定义过__func__,预处理器还定义了一些调试非常有用的名字。
    __FILE__ 存放文件名的字符串字面值
    __LINE__ 存放当前行号的整形字面值
    __TIME__ 存放文件编译时间的字符串字面值
    __DATE__ 存放文件编译日期的字符串字面值

    可以使用这些变量在错误消息中提供更多信息,例如:

    if(word.size() < minLen)
    cerr     << "Error : " << __FILE__
        << " : In function " << __func__
        << " at Line " << __LINE__ << endl
        << "    Compiled on " << __DATE__
        << " at time " << __TIME__ << endl
        << "    Word read was "" << word
        << "" : Length too short" << endl;

    如果提供一个小于minLen的变量,那么会得到类似如下的错误信息:

    Error : test.cpp : In function main at line 27
        Compiled on Jul 11 2019 at 20:00:00
        Word read was "foo" : Length too short
  • 相关阅读:
    PyQt5对话框
    PyQt5基础控件
    PyQt5主界面
    PyQt5入门
    ioctl太多虚拟内存不够用
    code principles
    Error: watch ENOSPC
    intelJ
    cas
    C的函数指针的作用,以及其赋值是弱类型的
  • 原文地址:https://www.cnblogs.com/HDK2016/p/10564411.html
Copyright © 2011-2022 走看看