【C++】C++中assert和ENDEGU预处理语句

assert

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

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

void assert (int expression);

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

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

好比:express

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

若是这个断言被触发,那么会获得相似于以下的错误信息:spa

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

这种状况,若是只看断言输出是得不到详细的信息,必须要去查看代码才能肯定是什么缘由致使了错误。

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

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

因为字符串字面值老是为true,因此整个表达式的真假性仍是取决于found变量。这样的话,既添加了额外的描述信息,又不改变原来的含义。
若是断言触发,会获得以下的结果:c++11

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

从断言输出的错误信息中,能够看到详细的错误描述。code

 

static_assert

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

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

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
相关文章
相关标签/搜索