【游戏编程精粹】Assert
1、格式
Assert(条件表达式)
2、表现
条件表达式为false时,弹出一个警告对话框。你可以忽略这个断言并继续执行你的代码、中断程序,或者直接中断到断言失败的代码。
3、特点
Assert宏不会被编译到最终发布版本,因此可以在开发期间大范围使用断言。
4、使用法则
不要在断言中调用函数或者修改任何变量,否则你的调试和发行版本将有不同的行为,导致难以预料的严重后果。
5、技巧
(1)一般我们是在assert内部写条件表达式。这样做能捕获异常情况,但是无法给开发人员提供更多的信息,我们可以在assert括号内写字符串,比如assert(length != 0 && “lenght equal zero”);
(2)有时我们会在代码运行不到的地方加一个assert(0),我们可以使用相同的技巧,通过简单的取反字符串导致失败来插入描述字符串。assert(!"The code shoule be never get here");
(3)前面两个技巧可以通过写一个简单的宏合并到一起。这个宏接受两个参数,第一个参数是需要计算的条件表达式,第二个参数是描述字符串。它模拟了前两个技巧,但便于输入和阅读。
#define Assert(a,b) assert(a && b)
使用:
Assert(src != 0, "lenght equal zero");
(4)标准c的断言会中断到assert.c文件中,而不是我们程序中断言出现的行。通过编写自己的assert宏,可以直接中断到输入断言的行
#if defined(_DEBUG) extern bool CustomAssertFunction(bool, int, char*, char*); #define Assert(exp,description)\ if(CustomAssertFunction((bool)(exp),description,__FILE__,__LINE__))\ {_asm{int 3}} #else #define Assert(exp,description) #endif bool CustomAssertFunction(bool, int, char*, char*) { ... }
(5)自己实现断言函数,还有其他好处。比如我们可以为自己的断言对话框添加一个总是“忽略”的选项,省的同一个断言触发几十次上百次,点都点不完。
实现方式:在函数内添加一个静态变量,通过这个变量决定是否执行:
if(CustomAssertFunction((bool)(exp),description,__FILE__,__LINE__))\
{_asm{int 3}}
(6)如果触发了一个基础函数内的断言,我们无法确定问题具体出现在哪,因为调用该函数的地方太多了。一个简单的办法就是在断言对话框中提供堆栈信息。
在Windows环境下,可以在断言对话框中提供一个按钮完成将信息复制到剪贴板的工作。只需要点几下鼠标,任何人都能轻松复制和粘贴assert到电子邮件或者错误报告中。
if (OpenClipboard(NULL)) { HGLOBAL hMem; char szAssert[256]; char * pMem; sprintf(szAssert, "Put assert info here"); hMem = GlobalAlloc(GHND | GMEM_DDESHARE, strlen(szAssert) + 1); if (hMem) { pMem = (char*)GlobalLock(hMem); strcpy(pMem, szAssert); GlobalUnlock(hMem); EmptyClipboard(); SetClipboardData(CF_TEXT, hMem); } CloseClipboard(); }
浙公网安备 33010602011771号