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, > &array, int index)
{
// 断言index的范围是[0,9]
assert(index >= && index <= ); // 这个是test.cpp的第7行
return array[index];
}
int main(int argc,char **argv){
  array<int,> array = {,,,,,,,,,};
  getArrayValue(array,-);//调用getArrayValue函数,传入一个错误的index值
return ;
}

会得到如下的报错信息:

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) == , "long must be 8 bytes");
int main(){return ;}

如果编译机器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, > &array, int index)
{
// 断言index的范围是[0,9]
assert(index >= && index <= ); // 这个是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
Compiled on Jul at ::
Word read was "foo" : Length too short

【C++】C++中assert和ENDEGU预处理语句的更多相关文章

  1. PHP中操作数据库的预处理语句

    今天这篇文章的内容其实也是非常基础的内容,不过在现代化的开发中,大家都使用框架,已经很少人会去自己封装或者经常写底层的数据库操作代码了.所以这回我们就来复习一下数据库中相关扩展中的预处理语句内容. 什 ...

  2. PHP中的MySQLi扩展学习(四)mysqli的事务与预处理语句

    对于 MySQLi 来说,事务和预处理语句当然是它之所以能够淘汰 MySQL(原始) 扩展的资本.我们之前也已经学习过了 PDO 中关于事务和预处理语句相关的内容.所以在这里,我们就不再多讲理论方面的 ...

  3. PHP中的PDO操作学习(二)预处理语句及事务

    今天这篇文章,我们来简单的学习一下 PDO 中的预处理语句以及事务的使用,它们都是在 PDO 对象下的操作,而且并不复杂,简单的应用都能很容易地实现.只不过大部分情况下,大家都在使用框架,手写的机会非 ...

  4. mysql中SQL执行过程详解与用于预处理语句的SQL语法

    mysql中SQL执行过程详解 客户端发送一条查询给服务器: 服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果.否则进入下一阶段. 服务器段进行SQL解析.预处理,在优化器生成对应的 ...

  5. 前端学PHP之PDO预处理语句

    × 目录 [1]定义 [2]准备语句 [3]绑定参数[4]执行查询[5]获取数据[6]大数据对象 前面的话 本来要把预处理语句和前面的基础操作写成一篇的.但是,由于博客园的限制,可能是因为长度超出,保 ...

  6. mysql之预处理语句prepare、execute、deallocate

    预制语句的SQL语法基于三个SQL语句: PREPARE stmt_name FROM preparable_stmt; EXECUTE stmt_name [USING @var_name [, @ ...

  7. php pdo预处理语句与存储过程

    很多更成熟的数据库都支持预处理语句的概念.什么是预处理语句?可以把它看作是想要运行的 SQL 的一种编译过的模板,它可以使用变量参数进行定制.预处理语句可以带来两大好处: 1.查询仅需解析(或预处理) ...

  8. MySQL预处理语句

    预制语句的SQL语法基于三个SQL语句: PREPARE stmt_name FROM preparable_stmt; EXECUTE stmt_name [USING @var_name [, @ ...

  9. PDO 学习与使用 ( 二 ) PDO 数据提取 和 预处理语句

    以数据库 msg 为例,说明 PDO 的数据提取.预处理语句: mysql> show tables;+---------------+| Tables_in_msg |+----------- ...

随机推荐

  1. 给力的移动 FZU - 2287

    你的弟弟给你安排了一个任务,他给了你1到N个数字的乱序排列,现在你想给你的弟弟秀一波操作,操作最少的次数把序列变成1到N的顺序排列,每次操作你可以选择序列中的一个数字并把它移动到序列的头部或尾部. I ...

  2. for循环以及数据类型

    一.for循环(迭代式循环) 了解:当我们在写代码时,如果代码是纯运算的代码,会占用大量的CPU,如果是I/O代码,则不会占用CPU. for i in range(10):  #可以是任意类型(字符 ...

  3. HNOI 2017

    题目链接 我还是按bzoj AC数量排序做的 4827 这个其实如果推一下(求每个值)式子会发现是个卷积,然后FFT就好了 4826 记不太清了,可以求出每个点左右第一个比他的的点的位置,将点对看成平 ...

  4. BZOJ2948 : [Poi2001]绿色游戏

    维护一个保护集合$S$,表示哪些点$A$可能胜利. 首先将所有绿点加入$S$. $1.$对于一个不在$S$的$A$点,若它存在某个后继在$S$中,则将其加入$S$. $2.$对于一个不在$S$的$B$ ...

  5. WC、KOI2017小随想..

    自从WC之后就一直想说些什么.. 嗯比较零碎.. Part A WC,我通过我的双眼看到了我想要的 嗯,就是在上面道出自己的想法.自己的思想 也是自己在十二月的迷茫后看到的曙光吧.. 感动.激动.难以 ...

  6. C++程序设计方法3:数组下标运算符重载

    数组下标运算符重载 函数声明形式 返回类型operator[](参数): 如果返回类型是引用,则数组运算符调用可以出现在等式的左边,接受赋值,即: Obj[index] = value; 如果返回类型 ...

  7. flask内容之数据库的管理

    #! /usr/bin/env python # *-* coding: utf-8 *-* from flask import Flask, flash, redirect from flask i ...

  8. 小甲鱼Python第五讲课后习题

    0.Python中,int表示整型 bool:布尔类型 float:浮点型 str:字符串类型 1.为什么布尔类型(bool)的TRUE和FALSE分别用0和1表示? 计算机只认识二进制,由于二进制只 ...

  9. Linux命令之vi篇

    作业二: 1)  使用vi编辑器编辑文件/1.txt进入编辑模式写入内容“hello world” [root@localhost ~]# vi 1.txt 2)  进入命令行模式复制改行内容,在下方 ...

  10. 移动端适配问题px->rem方法

    移动端web页面适配问题 1.引入插件 github地址:https://github.com/re54k/mobileweb-utilities/blob/master/util/mobile-ut ...