一直以来,对于assert的实现总是不太理解,现在深入assert背后的代码,总算对assert的实现有了一个清醒的认识。
assert基于宏定义与宏展开实现。首先介绍一下assert的功能:它能够断言给定表达式是否为true。如果为true,则对应assert的代码会转换为static_cast<void>(0)
,即一条空语句,assert不执行任何操作,否则assert对应的代码会展开为__assert_fail (__STRING(expr), __FILE__, __LINE__, __func__))
,使用expr参数,源代码名,assert所在的行数以及函数名调用__assert_fail
函数,输出错误信息,并且因为断言出错而终止程序。请注意,在调用函数__assert_fail
时,assert将传入的参数转换为字符串输入,这一点只需查看__STRING(x)
的定义:#define __STRING(x) #x
即可明白。
我们知道,在编译源代码的时候,如果我们定义了NDEBUG
,那么assert不会起任何作用,哪怕传入的参数为false
,这是为什么呢?因为在assert外层还有一个宏判断语句,如果定义了NDEBG
,那么assert语句统一转换成static_void<void>(0)
进行处理,所以不会对传入的参数进行任何判断。
下面附上相关代码,相信你现在会对assert有更加清晰的认识!
// (为了便于阅读,代码进行了部分修改)
#define __STRING(x) #x
#ifdef NDEBUG
# define assert(expr) (static_cast<void>(0))
#else
# define assert(expr) \
((expr) \
?static_cast<void>(0) \
: __assert_fail (__STRING(expr), __FILE__, __LINE__, __func__))
#endif