2024年3月14日发(作者:)
VC程序调试VC程序调试 调试是一个程序员最基本的技能,其重要性甚至超
过学习一门语言。不会调试的程序员就意味着他即使会一门语言,却不能编制出任
何好的软件。 一、VC程序调试方法 VC的调试功能:首先,再次强调要用Go命
令运行一个将要调试的程序;如果要中止调试状态下的运行程序可以点击Stop
Debugging命令,还可以通过Break选项以可恢复方式中断调试程序的运行流程
(用Restart选项可以重新开始运行程序);Step Into选项表示每次只执行一行语
句(单步执行),但如果当前代码是调用一个函数,那么Step Into表示进入该函
数,全部函数语句执行完后返回,而Step Over则是跳出这个函数;Step To Cursor
选项表示程序将执行到光标所在的可执行语句行上;在调试多线程程序时,可以在
线程函数或主应用程序线程中设置断点,还可以用Break选项结束线程后用
Threads选项查看运行线程列表,也可以选择悬挂和恢复每个线程;在设置断点
后,在VC "查看"菜单的"调试窗口"中可以查看变量、内存、调用堆栈、寄存器以
及反汇编语句。在程序中设置断点的方法是,点击要设置的代码行并点击设置代码
的工具栏按钮,会出现在代码行最左边的一个小黑点即是断点标志,这时再选Go
程序会在执行到端点处停下来,如果要继续执行可以再选Go。 通过选择VC"
工具"菜单下的"源浏览器"可以生成一个.BSC文件,使用浏览器可以从中发现多种
信息:程序中任何一个变量、函数、类或宏在何处定义及引用;可以列出所有声明
的函数类、变量、宏;可以发现调用一个指定函数的所有函数;可以找到一个指定
类的派生来源或者它派生出哪些类。 在使用微软程序开发库MSDN时,我们会发
现其中的VC示例经常采用看似多余的ASSERT语句,其作用就是使程序具有"维
护"性。对于Debug版本的VC程序,在遇到布尔值为FALSE的ASSERT语句处
停止,并显示Assertion Failed对话;如果设置为发布版,所有ASSERT语句都会
被预处理程序删除。ASSERT宏在发行版本中不起作用,而应该用VERIFY来进行
发行版的调试。如果发行版本运行有问题,可以先禁止所有代码优化再进行调试。
系统提供一系列特殊的函数或者宏来处理Debug版本相关的信息,如下: 宏名/函
数名 说明 TRACE 使用方法和printf完全一致,他在output框中输出调试信息
ASSERT 它接收一个表达式,如果这个表达式为TRUE,则无动作,否则中断当前
程序执行。对于系统中出现这个宏 导致的中断,应该认为你的函数调用未能满足
系统的调用此函数的前提条件。例如,对于一个还没有创建的窗口调用
SetWindowText等。 VERIFY 和ASSERT功能类似,所不同
的是,在Release版本中,ASSERT不计算输入的表达式的值,而VERIFY计
算表达式的值。 在安装好VC系统之后,在VC之外的程序组中有一个程序
Tracer是一个跟踪工具,在激活它后使用Go运行VC代码,在输出窗口就能够看
到程序运行过程中的内部过程,包括DLL调用等,你如果看不到任何输出,可以
转到菜单"查看"(View)点击"输出"(Output)。 其实,MFC自身就提供有错
误查找和TRACE语句,而TRACE语句的语法与printf非常类似,所以我们可以
在程序中直接加入这条跟踪命令,如下所示: // Example for TRACEint 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::Dumpvoid 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 functionsCMemoryState
msOld, msNew, msDif;oint(;CAge* page1 = new CAge( 21 ;CAge*
page2 = new
CAge( 22 ;lObjectsSince(;oint(;ence( msOld,
msNew ;atistics(; 代码运行的结果为: Dumping objects ->{2} a
CObject at $190A{1} a CObject at $18EAObject dump complete.0 bytes in 0 Free
Blocks8 bytes in 2 Object Blocks0 bytes in 0 Non-Object BlocksLargest number used: 8
bytesTotal allocations: 8 bytes 在MFC类和VC中本身就有"异常情况"这个概
念,并在此基础上形成它们处理系统错误和意外的主要机制。比如当系统内存分配
殆尽时,你的运行程序就会收到内存异常的消息。这样就给了程序员消除异常的机
会。 MFC中的异常情况主要有:CArchiveException表示档案文件载入或保存
时出错,CDBException属于数据库错误,CFileException为文件错误,
CMemoryException为调用new时发生分配错误,CNotSupportedException表示指
定操作不被支持,COleException表示在调用OLE操作时出错,CO
leDispatchException表示在OLE自动操作时出错,CResourceException表示资
源找不到或无法创建,CUserException用于通知用户错误。 MFC还包含一系
列以Afx-为词头的调试函数:AfxAbort可以在发生致命错误时异常终止程序,
AfxCheckMemory可以检查堆和剩余缓冲池的受损部分;AfxDoForAllClasses重声
明所有CObject的派生类;AfxDoForAllObject重声明堆上所有CObject派生的对
象;AfxEnableMemoryTracking启用或禁止内存追踪;AfxIsMemoryBlock用于确认
指针所指内存有效;AfxIsValidAddress用于确认地址是驻留在程序的内存区域内;
AfxIsValidString用于确认地址所指字符串有效;AfxSetAllocHook用于内存分配前
进行检测;AfxTraceEnabled启动或禁止输出跟踪,AfxTraceFlags则进一步定制跟
踪特征。 二、VC6.0与VC2008 Release版本调试参数设置比较 VC6.0Release版本
调试参数设置 VC2008 Release版本调试参数设置 三、注意细节 1、对于所有有返
回值的函数,都应该检查返回值,除非你确信这个函数调用绝对不会出错,或者不
关心它是否出错。 一些函数返回错误,需要用其他函数获得错误的具体信息。例
如accept返回INVALID_SOCKET表示accept失败,为了查明具体的失败原因,
应该立刻用WSAGetLastError获得错误码,并针对性的解决问题。 2、有些函数通
过异常机制抛出错误,应该用TRY-CATCH语句/TRY-CATCH-finally来检查错
误 。程序员对于能处理的错误,应该自己在底层处理,对于不能处理的,应该报
告给用户让他们决定怎么处理。如果程序出了异常,却不对返回值和其他机制返回
的错误信息进行判断,只能是加大了找错误的难度。 3、VC中要编制程序不应该
一开始就写cpp/h文件,而应该首先创建一个合适的工程。因为只有这样,VC才
能选择合适的编译、连接 选项。对于加入到工程中的cpp文件,应该检查是否在
第一行显式的包含stdafx.h头文件,这是Microsoft Visual Studio为了加快编译速度
而设置的预编译头文件。在这个#include "stdafx.h"行前面的所有代码将被忽略,所
以其他头文件应该在这一行后面被包含。 对于.c文件,由于不能包含stdafx.h,因
此可以通过Project settings把它的预编译头设置为“不使用”,方法是: 弹出Project
settings对话框 选择C/C++ Category选择Precompilation Header 选择不使用预编译
头。 4、用GetLastError来检测返回值,通过得到错误代码来分析错误原因 5、把
错误信息记录到文件中 6、查看API的错误码,在watch窗口输入@err可以查看或
者@err,hr,其中”,hr”表示错误码的说明。 7、查看数组中的值时,在watch窗口输
入数组名称,数组大小就可以查看里面的内容值。 8、Set Next Statement:该功能可
以直
接跳转到指定的代码行执行,一般用来测试异常处理的代码。 9、使用映射文
件调试 a、创建映射文件:Project settings中link项,选中Generate mapfile,输出
程序代码地址:/MAPINFO: LINES,得到引出序号:/MAPINFO: EXPORTS。 b、
程序发布时,应该把所有模块的映射文件都存档。 c、查看映射文件:见” 通过崩
溃地址找出源代码的出错行”文件。


发布评论