断言
断言(Assert)对于程序调试非常重要,在一些库的实现中,为了检查中间计算过程的错误,可以使用断言进行检查;C++中有标准的assert库,但本文中,尝试写一写自定义assert的实现,以更好地辅助我们进行debug。
原则
- 断言内的条件是无条件为true的,如果断言失败,意味着程序逻辑错误,即程序存在bug,应当被修复;
- 断言只在debug模式下使用,在release模式,应当屏蔽掉断言,以避免对运行速度和binary文件的大小的影响;
- 断言不应该用来作为输入的合法性检查,也不应该用于异常处理,只作为debug目的,并且assert检查失败的情况按照正常情况应该永远不会出现;
自定义assert
常见的assert形式如下:
- assert(expr)
- assert_eq(expr)
- assert_ne(expr)
- ...
我们通过C++宏来实现以上assert:
#include <iostream>
#define MY_ENABLE_ASSERT
void assert_fail(const char* file, int line, const char* func,
const char* expr, const std::string& msg) {
(void)file;
(void)line;
(void)func;
(void)expr;
(void)msg;
std::string err_msg = std::string("Assertion fails:") + expr + ", message:" + msg +
", at " + file + ":" + std::to_string(line) + ":" + func;
std::cout << err_msg << std::endl;
std::terminate();
}
#ifdef MY_ENABLE_ASSERT
#define MY_ASSERT(expr) \
do { \
if(!(expr)) { \
assert_fail(__FILE__, __LINE__, __func__, #expr, ""); \
} \
} while(0)
#define MY_ASSERT_EQ(a, b) \
do { \
using std::to_string; \
if ((a) != (b)) { \
assert_fail(__FILE__, __LINE__, __func__, #a " == " #b, \
std::to_string(a) + " != " + std::to_string(b)); \
} \
} while (0)
#define MY_ASSERT_NE(a, b) \
do { \
using std::to_string; \
if ((a) == (b)) { \
assert_fail(__FILE__, __LINE__, __func__, #a " == " #b, \
std::to_string(a) + " != " + std::to_string(b)); \
} \
} while (0)
#else
#define MY_ASSERT(expr) (void)0
#define MY_ASSERT_EQ(expr) (void)0
#define MY_ASSERT_NE(expr) (void)0
#endif
int main(int argc, char** argv) {
int data[5] = {1,2,3,4,5};
// int index = 5;
// MY_ASSERT(index < 5);
// std::cout << data[index] << std::endl;
// MY_ASSERT_EQ(3,3);
MY_ASSERT_NE(2,2);
}
以上程序输出:
Assertion fails:2 == 2, message:2 != 2, at my_assert.cpp:54:main