文档章节

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

o
 osc_y8yehimr
发布于 2019/03/20 13:38
字数 1281
阅读 4
收藏 0
c++

精选30+云产品,助力企业轻松上云!>>>

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

 

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
【C++】C++中assert和ENDEGU预处理语句

assert 断言语句是C++中的一种预处理宏语句,它能在程序运行时根据否定条件中断程序。 C++中的assert()函数可以实现断言功能,在使用assert函数之前应该先引入头文件。 函数: void assert ...

HDWK
2019/03/20
0
0
C++ primer (第五版) 杂记

C++ string #include <string>using std::string; string包含在头文件iostream.h中: #include <iostream>using std::string; int main(){ string s1 = "hello"; string s2 = "world"; std:......

卓尔
2014/06/14
82
0
【C++】尽量以const,enum,inline 替换 #define

视C++为一个语言联邦 今天的C++已经是个多重范型编程语言,同时支持过程形式、面向对象形式、函数形式、范型形式、元编程形式。为了理解C++,必须认识其主要的次语言,总共有四个: 1. C。C...

Tanswer_
04/01
0
0
C/C++ 中宏与预处理使用方法大全 (VC)

原文:C/C++ 中宏与预处理使用方法大全 (VC) 作者:Breaker C/C++ 中的宏 (#define) 与预处理 (#if/#ifdef/#pragma) 的使用方法大全、使用技巧 开发环境:VC 2005 关键字:宏, 预定义宏, 预处...

晨曦之光
2012/05/23
1.1W
0
C++预处理器

预处理器是一些指令,指示表一起在实际编译之前所需要完成的预处理。 所有的预处理器指令都是以井号(#)开头,只有空格字符可以出现在预指令处理之前。预处理指令不是C++语句,所以他们不会以...

osc_8cfq8uoa
2019/08/16
1
0

没有更多内容

加载失败,请刷新页面

加载更多

科技人文丨玻璃心:承受阈值与表达

大家好,我是SKODE。 有趣的灵魂,聊科技人文。 本系列博客地址:传送门 本文转载自B站:安慰记传送门 玻璃心是网络用语,意思是: 对负面事件的接受度很低 还有对别人可能给出的负面评价非常...

osc_u9mt0sus
41分钟前
20
0
迅睿CMS 游客不允许上传附件

游客不允许上传附件 迅睿CMS系统:https://www.xunruicms.com/ 本文档原文地址:https://www.xunruicms.com/doc/752.html...

迅睿CMS-PHP开源CMS程序
42分钟前
7
0
代理,注解,接口和实现类的小测验

* retention : 保留* policy : 策略 ps : 简单测试了一下手写代理,jdk动态代理,和cglib动态代理,根据其不同的结果分析其原理 一:测试目的 主要想看一下不同的代理模式对于目标类中方法上注...

岁一
42分钟前
12
0
V-Ray 5 For 3ds Max 正式发布:超越渲染 - 知乎

15个新功能,V-Ray5助你时间更节省,渲染更出色! 作者:ChaosGroup VRay 5 For 3ds Max 已正式发布! 2分钟视频,抢先预览新功能↓ 知乎视频 www.zhihu.com V-Ray 5 for 3ds Max 新增功能 ...

osc_o9u1um45
42分钟前
0
0
毕业的笑容和悲伤永远是校园的回忆

校园的风轻轻的拂过我的脸庞,风儿显得更加凉爽, 开满火红的凤凰树,染遍了校园的每个角落, 晚上那枝头蝉儿的竞相鸣奏,唱满了令人不舍的毕业歌, 它们彷彿告诉了我们要毕业了。 毕业典礼那...

瑾123
43分钟前
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部