你也可以通过我的独立博客 —— www.huliujia.com 获取本篇文章

assert简介

assert被C/C++用来判断某些条件是否成立,比如判断指针类型的大小sizeof(void*)是否大于8,或者判断malloc返回的指针是否为null。

assert的函数申明如下:

void assert( int expression );

如果expression为0,即false,assert就会把函数名,源代码文件名、当前行号发送给标准错误stderr,然后调用abort()终止执行。

什么时候使用assert

assert一般用于判断逻辑上一定为真的条件,如果条件不符合就会导致未定义行为(undefined behavior)时,就可以使用assert。

这里其实涉及到狭义约定(narrow contract)和广义约定(wide contract)的概念。所谓狭义约定,就是函数执行需要满足预定义的条件,如果不满足就会导致未定义行为,比如std::vector::operator[],如果传入的index等于或者超过vector的大小,就会导致undefined behavior。而使用广义约定的函数即使输入不符合预期,也不会出现未定义行为。比如std::vector::at(),如果输入的index超出范围,就会抛出一个异常。

如果函数使用狭义约定,那么就应当使用assert去检查输入是否合法,不合法就直接结束执行。如果使用广义约定,检查发现输入不符合预期,就应当抛出异常或者返回一个错误码或者采取其他操作,总之,采取的操作一定是预定义的,而不是未定义的。

assert只适合在debug版本中进行测试,release版本中应当禁用assert。C/C++提供了NDEBUG宏用于控制assert的行为,assert是默认生效的,如果定义了NDEBUG宏,assert就不会生效。

assert用法

int main()
{int num = 1;assert(num == 1); //true,断言成功num = 10;assert(num == 1); //false,断言失败return 0;
}

编译执行上述代码,输出如下:

Assertion failed: (num == 1), function main, file test.cpp, line 9.
[1]    65468 abort      ./test

可以看到第一个assert没有任何输出,断言是成功的。第二个assert断言失败了,输出了断言条件,函数名,源码文件名,assert所在行号。

static_assert

static_assert是C++11新增的静态断言关键字。assert是运行时断言,只有在执行到assert时才会进行判断。而静态断言是在编译时进行断言。所以断言的条件必须是编译时即可确定。比如断言sizeof(void*)是否为8个字节,比如断言一个MACRO是否为某个值等。而判断malloc返回的指针是否为空就不能用static_assert了。

static_assert的声明如下:

static_assert ( bool_constexpr , message )

可以看到这不是一个函数的声明,因为static_assert是关键字,不是和assert一样的库函数。bool_constexpr是指布尔常量表达式,这里有两个含义,首先是布尔表达式,这点和assert要求相同。其次需要是常量表达式,常量表达式的意思是表达式的值是可以在编译阶段确定的,比如上面说的sizeof(void*)就是一个常量表达式。

message是断言失败时打印的错误提示,这点就比assert要方便一些,可以打印一些错误提示。

我们编写一个例子测试一下static_assert。

int main()
{static_assert(sizeof(void*) >= 8, "void*'s size is less than 8 bytes");static_assert(sizeof(void*) == 7, "void*'s size is not 7 bytes");return 0;
}

我们把上面的代码保存为test.cpp,编译一下看看,编译输出如下:

$g++ test.cpp -o test -std=c++11
test.cpp:5:5: error: static_assert failed due to requirement 'sizeof(void *) == 7' "void*'s size is not 7 bytes"static_assert(sizeof(void*) == 7, "void*'s size is not 7 bytes");^             ~~~~~~~~~~~~~~~~~~
1 error generated.

可以看到在第二个static_assert处报错了,因为sizeof(void ) == 7的求值结果是false。除了打印出了源码文件名、所在行,还打印了错误提示:"void’s size is not 7 bytes"。

第一个static_assert断言sizeof(void*) >= 8,因为我是在64bit机器上编译的,默认编译为64bit的二进制,所以这个断言是成功,那么如果我们改一下编译指令,编译成32bit的程序呢?

我们给g++加上-m32参数,表示编译生成32bit的二进制,编译输出如下:

$ g++ test.cpp -o test -std=c++11 -m32
test.cpp:3:5: error: static_assert failed due to requirement 'sizeof(void *) >= 8' "void*'s size is less than 8 bytes"static_assert(sizeof(void*) >= 8, "void*'s size is less than 8 bytes");^             ~~~~~~~~~~~~~~~~~~
test.cpp:5:5: error: static_assert failed due to requirement 'sizeof(void *) == 7' "void*'s size is not 7 bytes"static_assert(sizeof(void*) == 7, "void*'s size is not 7 bytes");^             ~~~~~~~~~~~~~~~~~~
2 errors generated.

因为sizeof(void*)此时的值为4,所以两个断言都失败了。

static_assert有两个参数,第二个参数message可以用来打印错误提示,如果不想打印错误提示呢?在C++17之前,只能把第二个参数置为空字符串,C++17开始,message参数成为可选项,可以只填第一个参数。

在C语言中使用static_assert

C11之后可以使用Static_assert ( expression , message )

C23开始支持_Static_assert ( expression )

老版本也可能支持,但是得看编译器了=_=

如何让assert也能打印错误提示

assert并没有直接支持打印错误提示的接口,但是通过一些奇技淫巧可以实现这个功能,我们把上面的例子修改一下:

int main()
{int num = 1;assert(num == 1 && "num should be 1"); //true,断言成功num = 10;assert(num == 1 && "num should be 1"); //false,断言失败return 0;
}

这个利用了aseert会把断言表达式打印出来这个特性,而字符串的值是一个非0指针,所以&&右侧必然为True,不影响断言结果。

我们执行上面的代码,结果如下

$ ./test
Assertion failed: (num == 1 && "num should be 1"), function main, file test.cpp, line 8.
[1]    79622 abort      ./test

参考文献

Assertions in C/C++
When is assert() to be used?
static_assert declaration
Static assertion
Add custom messages in assert? - Stack Overflow

C/C++中的断言(assert与static_assert)相关推荐

  1. 理解和正确使用Java中的断言(assert)

    理解和正确使用Java中的断言(assert) 一.语法形式:     Java2在1.4中新增了一个关键字:assert.在程序开发过程中使用它创建一个断言(assertion),它的 语法形式有如 ...

  2. Java中的断言(assert)

    为什么80%的码农都做不了架构师?>>>    一.语法形式:     Java2在1.4中新增了一个关键字:assert.在程序开发过程中使用它创建一个断言(assertion), ...

  3. python断言assertequal_python中那个断言assert的优化

    Python Assert 为何不尽如人意# Python中的断言用起来非常简单,你可以在assert后面跟上任意判断条件,如果断言失败则会抛出异常. Copy >>> assert ...

  4. java 断言assert_Java中的断言 Assert

    今天正好遇到了,就记一下 一.作用: 仅用与编写单元测试, 一般不用于生产环境 assert 理论上和 if 类似, 但是assert 仅仅用于测试, 不能用于业务 from jdk 1.4 二.as ...

  5. java assert false_深入剖析Java中的断言assert

    Java陷阱之assert关键字 一.概述 在C和C++语言中都有assert关键,表示断言. 在Java中,同样也有assert关键字,表示断言,用法和含义都差不多. 二.语法 在Java中,ass ...

  6. java 断言 assert 详解:断言开启、断言使用

    java中的断言Assert的使用 一.背景 二.如何判断是否开启了断言 三.开启断言 四.断言的使用 方法一.assert <boolean表达式> 方法二.assert <boo ...

  7. python断言assert实例_python接口测试assert断言

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! unittest.texttestrunner(verbosity=2).run ...

  8. java断言assert的概念_断言(assert)简介

    java中的断言assert的使用 一.assertion的意义和用法 J2SE 1.4在语言上提供了一个新特性,就是assertion功能,他是该版本再Java语言方面最大的革新. 从理论上来说,通 ...

  9. Linux C 中断言assert()使用简介

    assert()是一个调试程序时经常使用的宏,在程序运行时它计算括号内的表达式,如果表达式为FALSE (0), 程序将报告错误,并终止执行.如果表达式不为0,则继续执行后面的语句,它的作用是终止程序 ...

最新文章

  1. [转]如何在保证睡眠的情况下高效学习
  2. Spring Cloud Alibaba基础教程:Nacos的数据持久化
  3. Play和Grails Java框架的优缺点
  4. python向服务器请求压缩数据及解压缩数据
  5. java divide 用法_java中BigDecimal加减乘除基本用法
  6. [leetcode]207. Course Schedule课程表
  7. Rabbtmq Confirm 确认消息
  8. Android Stdio4.1.1版本使用问题
  9. Github 插件之 Octotree 报错介绍与解决
  10. java 将map转List对象
  11. 最新美团Java面试题目(共3面)
  12. 51单片机系列--蜂鸣器
  13. 北京大学创业训练营专家讲座:创新大师乔布斯的创业理念与营销哲学
  14. 自然语言处理 # 中文分词技术 概述
  15. JAVA试题(100道)
  16. linux yum vsftpd,CentOS 7 使用Yum方式安装配置vsftpd服务
  17. java大文件pdf水印_java – 如何扩展PDF的页面大小以添加水印?
  18. 机器学习周志华——机器学习的应用领域
  19. EmpireToken创造超级代币
  20. ubuntu多显卡风扇转速控制

热门文章

  1. Win7下Nginx的安装与配置,win7nginx配置
  2. CSS:文本阴影(重影)效果(text-shadow)
  3. 今天继续去新交房的小区地推
  4. 古建筑测绘方法及流程介绍
  5. HIT-SC 正则表达式(JAVA)
  6. 污力滔滔的香蕉先生,竟然还可以用来做这种事丨钛空舱
  7. android高德地图设置缩放级别,设置地图中心点/级别
  8. 【投资理财】期权的价值
  9. 投资理财-如何看公司
  10. 移动应用“来电通”开发者赚到第一桶金