参考
http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
1
#define POW2_ASSERT(x) \
if (!x) { pow2::Assert::Fail(#x, __FILE__, __LINE__); }
这是最一开始的样子
那么POW2_ASSERT(true || false);
就会变成
if (!true || false) { pow2::Assert::Fail(...); }
2
所以加括号:
#define POW2_ASSERT(x) \
if (!(x)) { pow2::Assert::Fail(#x, __FILE__, __LINE__); }
那么
if (x == 3)
POW2_ASSERT(y == 4);
else
DoSomethingReallyImportant();
就会变成
if (x == 3)
if (!(y == 4))
pow2::Assert::Fail(...);
else
DoSomethingReallyImportant();
破坏了if else
3
所以把宏定义用do { … } while(0)包起来
于是就变成了:
#define POW2_ASSERT(x) \
do { if (!(x)) { pow2::Assert::Fail(#x, __FILE__, __LINE__); } } while(0)
如果要写成带有宏开关,设定是否要开启assert的情况:
#ifdef POW2_ASSERTS_ENABLED
#define POW2_ASSERT(x) \
do { if (!(x)) { pow2::Assert::Fail(#x, __FILE__, __LINE__); } } while(0)
#else
#define POW2_ASSERT(x)
#endif
我们设置为不开启
然后像这样调用
const bool success = DoStuff(); POW2_ASSERT(success);
某些环境下会产生warning:
main.cpp(7) : warning C4189: 'success' : local variable is initialized but not referenced
4 所以我们把它转换成void
#define POW2_ASSERT(x) do { (void)(x); } while(0)
那么如果
int main(int, char*[])
{
bool DoStuff(); // comes from another .cpp file
POW2_ASSERT(DoStuff());
return 0;
}
编译器不知道DoStuff是什么,gcc下它会被调用
虽然warning被消除了但是有副作用
那么怎么能保证不执行DoStuff呢?
我们给它加一个 sizeof
5 于是
#ifdef POW2_ASSERTS_ENABLED
#define POW2_ASSERT(x) \
do { if (!(x)) { pow2::Assert::Fail(#x, __FILE__, __LINE__); } } while(0)
#else
#define POW2_ASSERT(x) \
do { (void)sizeof(x); } while(0)
#endif
6 有的时候我们希望assert了之后还可以continue
就需要我们自己定义handler来替换__debugbreak()
dt里面的写法:
/// An assertion failure function.
// @param[in] expression asserted expression.
// @param[in] file Filename of the failed assertion.
// @param[in] line Line number of the failed assertion.
/// @see dtAssertFailSetCustom
typedef void (dtAssertFailFunc)(const char* expression, const char* file, int line);
/// Sets the base custom assertion failure function to be used by Detour.
/// @param[in] assertFailFunc The function to be invoked in case of failure of #dtAssert
void dtAssertFailSetCustom(dtAssertFailFunc *assertFailFunc);
/// Gets the base custom assertion failure function to be used by Detour.
dtAssertFailFunc* dtAssertFailGetCustom();
# include <assert.h>
# define dtAssert(expression) \
{ \
dtAssertFailFunc* failFunc = dtAssertFailGetCustom(); \
if(failFunc == NULL) { assert(expression); } \
else if(!(expression)) { (*failFunc)(#expression, __FILE__, __LINE__); } \
}
#endif