在VC开发过程中,我们会经常使用系统定义的一些宏来帮助我们做调试判断,其中有我们十分常用的TRACE和ASSERT这两个宏。但是,这两个宏一定需要慎用,之前在接手别人的代码时,就因为ASSERT而导致了非常麻烦的问题。现在将ASSERT的一些注意的地方描述出来,以供参考。
ASSERT这个宏是一个断言,用法为ASSERT(条件)。只有当条件为0时,才会触发断言,因此在DEBUG模式下,我们经常会通过使用它来判断一些函数是否执行成功。例如,我们现在举例调用。
intAPIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE,szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_MFCTEST,szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
ASSERT(InitInstance(hInstance, nCmdShow));
if (!InitInstance (hInstance,nCmdShow))
{
return FALSE;
}
hAccelTable =LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MFCTEST));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if(!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
上述代码中,我们对初始化进行断言判断,当初始化失败的时候,触发断言。而运行效果如图所示:
即程序会在此处崩溃,有利于我们进行调试代码。但是,一旦进入release模式进行编译时,情况就完全不一样了。在release模式下,会直接跳过ASSERT这个宏,以及这个宏中的条件判断式的执行。这个时候,比如上述ASSERT(InitInstance(hInstance,nCmdShow));中,则会忽略initInstance(hInstance,nCmdShow);这个函数的执行。而这个就是造成恐怖的根源。我们调用ASSERT宏定义的声明看一下,如下:
#defineASSERT(f) DEBUG_ONLY((void) ((f)|| !::AfxAssertFailedLine(THIS_FILE, __LINE__) || (AfxDebugBreak(), 0)))
这里有明确的描述,只在debug模式下有效。
那么,如果说这个时候,要将CPP中所有的ASSERT去掉的话,也是不现实的,工作量很大而且不利于调试代码。那么怎么办呢?我这里推荐一个方法,即我们对ASSERT这个宏进行添加一层宏定义,让他只在DEBUG模式下运行。代码如下:
#ifdef_DEBUG//此处应该为_DEBUG而非DEBUG,前者为编译命令集合中的内容
#define DEBUGASSERT ASSERT
#else
#define DEBUGASSERT TRUE&&
#endif