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. TF之RNN:基于顺序的RNN分类案例对手写数字图片mnist数据集实现高精度预测—Jason niu

    import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data mnist = input_dat ...

  2. Java数组实现循环队列的两种方法

    用java实现循环队列的方法: 1.添加一个属性size用来记录眼下的元素个数. 目的是当head=rear的时候.通过size=0还是size=数组长度.来区分队列为空,或者队列已满. 2.数组中仅 ...

  3. ThreadPoolExecutor 入参 corePoolSize 和 maximumPoolSize 的联系

    前言 我们可以通过 java.util.concurrent.ThreadPoolExecutor 来创建一个线程池: new ThreadPoolExecutor(corePoolSize, max ...

  4. (Zero XOR Subset)-less-线性基

    (Zero XOR Subset)-less 题意 :把n个数分成多个集合,要求 不能有集合为空,最终不能有非空子集合异或值为0,尽可能划分的多一些. 思路 :非法情况就只有 n个数异或 为0,其他的 ...

  5. 解决UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range

    字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(en ...

  6. C++多态实现原理详解

    C++的多态性用一句话概括就是:在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数.如果对象类型是派生类,就调用派生类的函数:如果对象类型是基类 ...

  7. JavaScript基础笔记(十三)测试和调试

    错误处理与测试 一.错误处理 一)try-catch语句 function atest() { try { //可能发生错误的代码 return 0; } catch (error) { //错误处理 ...

  8. [蓝点ZigBee] Zstack 之点亮OLED液晶 ZigBee/CC2530 视频资料

    这一小节主要演示如何在Zstack 下移植液晶驱动,我们选取了目前比较流行的OLED 作为移植目标. 移植关键点 1 修改 GPIO pin,                  2 如何将Zstack ...

  9. java输出格式-----System.out.printf()

    package com.lzc.test; public class Main { public static void main(String[] args) { // 定义一些变量,用来格式化输出 ...

  10. jquery 获取奇数索引的元素,获取复选框,判断是否选中

    $(".btn-xs:odd").click(function(){ var $buy_num=$(this).prev("#buy_num").val(); ...