asserts in C++
1 assert
#include <cassert>
void assert(int expression);
assert宏用于判断expression是否为0,为0则向stderr打印一条出错信息,然后调用abort终止程序。但是,assert只对于debug有效,在release中会变成空语句,因为它的具体定义依赖于NDEBUG宏是否定义。assert的诊断信息中会包含expression及标准宏__FILE__, \(\text{__LINE__}\), __func__的值。
还要注意,由于assert是一个宏,expression中的逗号,会被当成参数分隔符,如:
assert(std::is_same_v<int, int>); // error: assert does not take two arguments
assert((std::is_same_v<int, int>)); // ok
2 release assert
如果我们想要在release版本中使用assert怎么办。一种方案是
#undef NDEBUG
#include <cassert>
还有一种我觉得更好的是使用glog提供的CHECK宏,具体有:
判断大小关系,CHECK_EQ, CHECK_NE, CHECK_LE, CHECK_LT, CHECK_GE, CHECK_GT。
CHECK_NOTNULL(some_ptr) 判断指针非空,通常用于参数检查。
字符串比较,CHECK_STREQ, CHECK_STRNE, CHECK_STRCASEEQ, CHECK_STRCASENE。
浮点数相等判断,CHECK_DOUBLE_EQ, CHECK_NEAR。
还有CHECK_INDEX, CHECK_BOUND判断是否有效的数组下标及上界,但是这两个都要求静态数组,因为是用sizeof计算的。
当这些宏的条件不成立时,glog会LOG(FATAL)打印相关的参数并终止程序,同时这些宏本质上都是输出流,你也可以添加自己的日志消息,像这样:
CHECK_NE(1, 2) << ": the world must be ending!";
3 static_assert
C++11提供了static_assert,能够实现编译期assert。
static_assert(bool_expression, message);
bool_expression为false时会终止编译,并将message打印在编译错误中,注意,message必须为字符串字面量,不能容纳动态信息,这也不难理解,毕竟是一个编译期的动作。
static_assert可以用来做一些环境检查,比如你的代码依赖于32-bit的unsigned int, 可以添加如下的static_assert,
static_assert(sizeof(unsigned int) * CHAR_BIT == 32, "unsigned int is not exactly 32-bit");
如果某平台的unsigned int不是32bit,编译会失败从而提醒开发者修改实现。