在使用微软程序开发库MSDN时,我们会发现其中的VC示例经常采用看似多余的ASSERT语句,其作用就是使程序具有"维护"性。对于Debug版本的VC程序,在遇到布尔值为FALSE的ASSERT语句处停止,并显示Assertion Failed对话;如果设置为发布版,所有ASSERT语句都会被预处理程序删除。一个地道的VC编程员,应该有意在自己的代码中通过"维护"特征去检测任何设定,诸如输入参数、循环范围和变量值的设定。
在安装好VC系统之后,在VC之外的程序组中有一个程序Tracer是一个跟踪工具,在激活它后使用Go运行VC代码,在输出窗口就能够看到程序运行过程中的内部过程,包括DLL调用等,你如果看不到任何输出,可以转到菜单"查看"(View)点击"输出"(Output)。
其实,MFC自身就提供有错误查找和TRACE语句,而TRACE语句的语法与printf非常类似,所以我们可以在程序中直接加入这条跟踪命令,如下所示:
// Example for TRACE int i = 1; char sz[] = "one"; TRACE( "Integer = %d, String = %s\n", i, sz ); // Output: 'Integer = 1, String = one' |
在Developer Studio中还提供了一个ERRLOOK工具,程序员只要输入错误号就能得到系统出错信息或模块错误内容。
MFC从Cobject派生的每个类都包含一个Dump函数,该函数可把当前状态转储(Dumping)到输出窗口,这在某些调试过程中会有用,以下代码是Dump函数的用法:
// Example for CObject::Dump void CAge::Dump( CDumpContext &dc ) const { CObject::Dump( dc ); dc << "Age = " << m_years; } |
在MFC中还有一个非常有用的类是CMemoryState,我们可以在程序的任何部分使用这个类检测内存冲突,并得到内存冲突的确切位置。CMemoryState类有3个成员函数:CheckPoint可将堆的当前状态存入类的实体;Difference可以比较两个实体包含的堆之间的差异;DumpStatistics用于标准化转储所有被CheckPoint捕获后分配到堆的对象,如CheckPoint未被调用实体未被初始化时,该函数将转储当前堆的所有内容。以下代码表示了CMemoryState类的使用方法:
// Example for CMemoryState::CMemoryState, // Includes all CMemoryState functions CMemoryState msOld, msNew, msDif; msOld.Checkpoint(); CAge* page1 = new CAge( 21 ); CAge* page2 = new CAge( 22 ); msOld.DumpAllObjectsSince(); msNew.Checkpoint(); msDif.Difference( msOld, msNew ); msDif.DumpStatistics(); |
代码运行的结果为:
Dumping objects -> {2} a CObject at $190A {1} a CObject at $18EA Object dump complete. 0 bytes in 0 Free Blocks 8 bytes in 2 Object Blocks 0 bytes in 0 Non-Object Blocks Largest number used: 8 bytes Total allocations: 8 bytes |
在MFC类和VC中本身就有"异常情况"这个概念,并在此基础上形成它们处理系统错误和意外的主要机制。比如当系统内存分配殆尽时,你的运行程序就会收到内存异常的消息。这样就给了程序员消除异常的机会。
MFC中的异常情况主要有:CArchiveException表示档案文件载入或保存时出错,CDBException属于数据库错误,CFileException为文件错误,CMemoryException为调用new时发生分配错误,CNotSupportedException表示指定操作不被支持,COleException表示在调用OLE操作时出错,COleDispatchException表示在OLE自动操作时出错,CResourceException表示资源找不到或无法创建,CUserException用于通知用户错误。
MFC还包含一系列以Afx-为词头的调试函数:AfxAbort可以在发生致命错误时异常终止程序,AfxCheckMemory可以检查堆和剩余缓冲池的受损部分;AfxDoForAllClasses重声明所有CObject的派生类;AfxDoForAllObject重声明堆上所有CObject派生的对象;AfxEnableMemoryTracking启用或禁止内存追踪;AfxIsMemoryBlock用于确认指针所指内存有效;AfxIsValidAddress用于确认地址是驻留在程序的内存区域内;AfxIsValidString用于确认地址所指字符串有效;AfxSetAllocHook用于内存分配前进行检测;AfxTraceEnabled启动或禁止输出跟踪,AfxTraceFlags则进一步定制跟踪特征。