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. java.lang.NoClassDefFoundError: org/apache/hadoop/hbase/HBaseConfiguration] with root cause

    在用Java web和hbase连接时,报出来这个错误,一开始我以为是hbase导入的包位置不对,不从build path那里导入,而是从WEB-INF下的lib中导入,尝试了之后结果仍是这个错误 十 ...

  2. Xamarin Essentials教程实现数据的传输功能实例

    Xamarin Essentials教程实现数据的传输功能实例 [示例1-1]以下将实现数据的传输功能.代码如下: public async Task ShareUri(string text, st ...

  3. WPF DataGrid 每行ComboBox 内容不同的设置方法

    <toolkit:DataGridComboBoxColumn x:Name="DgCbcSignal" Header="信号源" SelectedIte ...

  4. spring boot + jpa + bootstrap + thymeleaf 简单的增删改查Demo

    对springboot和bootstrap初学者来说是一个不错Demo 下载地址:点击进入下载Demo 首页(http://localhost:8081) 增加 编辑 搜索

  5. 解决Echarts封装成组件时只有最后一个才会缩放的问题

    参考了此文,并且强烈建议去看http://blog.csdn.net/crper/article/details/76091755 一般网上的方法都是 mounted() { this.drawCha ...

  6. 2046 ACM 数学

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=2046 思维:与之前有两道题目相似,n可以由n-1和n-2递推过来.f(n)=f(n-1)*1+f(n-2) ...

  7. js点击回到顶部2

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>点 ...

  8. C#7.0&6.0新特性 — 完整版

    C#2.0 泛型 部分类型 匿名方法 迭代器 可空类型 Getter / setter单独可访问性 方法组转换(代表) Co- and Contra-variance for delegates 静态 ...

  9. sublime Text3 插件

    sublime  Text3 插件大全以及使用方法 参考网址: https://www.cnblogs.com/qqing/p/6872195.html

  10. 获取html下的所有纯文本的方法

    第一种是看别人博客的,第二种是自己发现的. 第一种: #-*- coding: utf8 -*- import re html = """ <div class=& ...