第二章调试和错误处理技巧.docx
- 文档编号:14340910
- 上传时间:2023-06-22
- 格式:DOCX
- 页数:45
- 大小:226.24KB
第二章调试和错误处理技巧.docx
《第二章调试和错误处理技巧.docx》由会员分享,可在线阅读,更多相关《第二章调试和错误处理技巧.docx(45页珍藏版)》请在冰点文库上搜索。
第二章调试和错误处理技巧
第二章调试和错误处理技巧
在本章中,我们将介绍ViusalStudio调试器的一些主要特性,并介绍如何利用调试处理应用程序中的错误和异常。
调试器是一个功能非常强大的工具,使用该工具可以方便地识别和去除应用程序代码中的逻辑错误。
此外,一些由外部软件或硬件环境引起的异常情况的发生,也会影响应用程序的性能,通过添加一些必要异常处理代码,会避免程序崩溃的事件发生,从而使得程序能够在自己的控制下顺利执行。
本章中将介绍下面这些内容:
Ø使用VisualStudio调试器识别和消除程序中的错误。
Ø使用EditandContinue功能简化调试过程。
Ø使用内置的错误处理代码编写函数。
Ø使用C++异常处理技术处理运行过程中出现的异常错误。
Ø介绍并使用各种MFC异常类。
2.1调试
在本节中,我们将介绍VisualStudio调试器属性、界面以及EditandContinue特性的使用。
2.1.1调试概述
我们通常所说的应用程序错误,是指由于某些可控参数或条件的影响,使得某个函数或者进程不能顺利执行指定的任务。
比如,当没有连接某个文档时,CView:
:
GetDocument函数将返回一个NULL(空)指针,这时就可以使用VisualStudio调试工具在程序代码中校正这些错误。
下面我们介绍VisualStudio调试器功能和界面。
VisualStudio调试器中的工具很强大,能帮助你测试C++、MFC以及混合语言应用程序。
VisualStudio调试功能包括如下几个方面:
Ø设置断点
Ø逐步调试代码
Ø监视变量、注册表和内存
Ø查看代码和调用堆栈
Ø修改代码和变量的值
二、VisualStudio调试器界面
VisualStudio调试器界面包含下面这些内容:
1.和调试有关的菜单
和调试有关的菜单包括Build菜单、Debug菜单、View菜单和Edit菜单,下面我们介绍一下Build菜单和Debug菜单。
ØBuild菜单
Build菜单包含的内容如图2-1所示。
图2-1Build菜单
值得注意的是,创建一个应用程序后,Build菜单各项命令将有些变化,在有些命令后会带上具体应用程序的名称,而且包含的内容也比没有创建项目空间时多。
下面我们介绍图2-1所示菜单中的各项命令。
Compile命令表示编辑当前的源代码文件,在本例中,CompileMyFirstView.cpp表示编辑MyFirstView.cpp文件。
Build命令表示编译当前的可执行文件,在这里,BuildMyFirst.exe表示编译当前的MyFirst.exe文件。
RebuildAll命令表示编译项目中的所有文件。
BatchBuild…命令用于对项目中文件进行有选择的编译,执行该命令后,屏幕上就会弹出如图2-2所示的对话框。
在图2-2所示对话框中,ProjectConfigurations框列出项目的所有配置形式,如果将它们都选中,则表示对这两种形式的项目都进行编译,当然你可以根据自己的需要选择其中的一种形式。
在图2-2中,Build按钮用于对指定形式项目进行编译,Clean按钮用于删除指定项目的中间文件和输出文件,但并不对项目进行编译,而RebuildAll既删除指定项目的中间文件和输出文件,又对项目进行编译,相当于进行了Clean和Build两个命令执行的操作。
如果选中Selectiononly复选框,则表示只对选中项目进行编译,而对与该项目有依赖关系的项目不进行编译。
图2-2BatchBuild对话框
Clean命令表示删除当前形式项目的中间文件和输出文件。
StartDebug子菜单包含的内容如图2-3所示。
图2-3StartDebug子菜单
在图2-3所示StartDebug子菜单中,Go命令用于执行程序代码直到程序中的断点处,如果没有断点,就会一直执行下去,直到程序的结尾。
StepInto表示逐步执行程序代码,如果一条语句中调用了某个函数,执行StepInto命令时,还会进入函数内部执行。
RuntoCursor命令表示执行程序代码直到遇到插入点为止。
AttachtoProcess…命令表示给某个正在运行的程序附加上调试操作,这样就可以中断正在运行的程序,而进行调试操作。
DebuggerRemoteConnection…命令用于设置远程连接调试选项,执行该命令后,屏幕上就会出现如图2-4所示的对话框。
在图2-4所示对话框中,Platform编辑框用于设置将要连接的计算机类型,Connection用于设置计算机连接的方式。
Execute命令用于执行编译成功的文件,在这里是ExecuteMyFirst.exe,即表示执行MyFirst.exe文件。
图2-4远程连接设置对话框
SetActiveConfiguration…命令用于设置活动项目形式,执行该命令,屏幕上就会出现如图2-5所示的对话框。
图2-5设置活动项目形式对话框
在图2-5所示对话框中,Projectconfigurations框用于选择活动项目的形式,例如,如果将MyFirst-Win32Debug设置成活动项目时,当对当前项目进行编译、连接时,表示只对Debug形式的MyFirst项目进行这些操作。
Configurations…命令用于设置项目空间及其配置,执行该命令后,屏幕上出现相应的对话框,如图2-6所示。
在图2-6所示对话框中,ProjectandConfigurations框中列出的是当前的项目空间及其配置,右边的Add…按钮用于添加配置到当前的项目以及相应的配置结构中,Remove按钮用于删除选中项目中的配置,值得注意的是,当将一个项目中的所有配置都删除后,这个项目也就不存在了。
图2-6Configurations对话框
Profile…用于设置和函数调用、运行时间等操作有关的一系列选项。
ØDebug菜单
Debug菜单包含的内容如图2-7所示。
图2-7Debug菜单
Debug菜单各项命令的含义如下:
Go和Build中StartDebug子菜单下的Go命令作用相同,用于执行程序代码直到程序中的断点处。
Restart表示重新对程序进行调试,对应的快捷键为Ctrl+Shift+F5。
StopDebugging命令用于终止调试过程,返回到编辑状态。
Break命令用于中断正在进行的调试操作。
ApplyCodeChanges命令用于应用对代码所作的改变。
StepInto命令用于逐步调试程序,而且遇到程序中调用的函数时,进入函数内部执行。
StepOver命令也是逐步调试程序,但是当遇到调用函数时,并不进入函数内容执行。
StepOut命令在进行调试程序时,从正在执行的某个嵌套结构的内部跳到该结构的外部,常用于知道调用函数中不存在错误的情况。
RuntoCursor命令用于调试程序直到插入点处。
StepIntoSpecificFunction命令也是逐步进行程序代码的调试,而且还会进入指定函数的内部。
Exceptions…命令用于设置异常处理的一些参数,执行该命令后,屏幕上就会显示如图2-8所示的对话框。
图2-8Exceptions对话框
在图2-8所示的Exceptions对话框中,Number和Name分别表示异常的编号和名称。
Action框用于设置遇到异常后,系统执行什么操作,包含两个选项:
Stopalways和Stopifnothandled,前者表示遇到异常就停止执行,而后者表示如果这些异常没有处理,就停止执行。
对话框右边的Add和Remove按钮分别用来添加和删除异常,Change按钮用于改变异常对应的Action状态。
接下来的Module…命令用于显示模块列表,执行该命令后,屏幕上就会出现如图2-9所示的对话框。
在图2-9所示的模块列表对话框中,三列分别列出的是模块的名称、地址以及所在的路径。
ShowNextStatement命令用于显示程序代码中当前位置的下一条语句。
图2-9模块列表对话框
QuickWatch…命令用于快速查看表达式等的值,执行该命令后,屏幕上就会出现如图2-10所示的对话框。
图2-10QuickWatch对话框
在图2-10所示对话框中,既可以在Expression编辑框中直接键入相应的表达式,也可以首先选中程序中的某个表达式,然后再执行QuickWatch…命令查看其值。
到这里为止,Build菜单和Debug菜单就全部介绍完了。
2.调试工具栏
使用调试工具栏,可以使程序的调试过程变得简洁,在菜单栏上空白地方单击鼠标右键,就会弹出一个菜单,选中这个菜单中的Debug选项,随后屏幕上就会出现如图2-11所示的调试工具栏。
图2-11Debug工具栏
我们将Debug工具栏中的各个按钮代表的含义列在表2-1中。
表2-1Debug工具栏各按钮代表的含义
按钮
含义
快捷键
从头开始调试,对应于Debug菜单中的Restart命令。
Ctrl+Shift+F5
停止调试程序,对应于Debug菜单中的StopDebugging命令。
Shift+F5
暂时中断调试程序,对应于Debug菜单中的Break命令。
应用改变的代码,对应于Debug菜单中的ApplyCodeChanges命令。
Alt+F10
显示下一个语句,对应于Debug菜单中的ShowNextStatement命令。
Alt+Num*
逐步调试程序,并进入调用函数内部执行,对应于Debug菜单中的StepInto命令。
F11
也是逐步调试程序,但是当遇到调用函数时,并不进入函数内容执行。
对应于Debug菜单中的StepOver命令。
F10
在进行调试程序时,从正在执行的某个嵌套结构的内部跳到该结构的外部,常用于知道调用函数中不存在错误的情况。
对应于Debug菜单中的StepOut命令。
Shift+F11
用于调试程序直到插入点处,对应于Debug菜单中的RuntoCursor命令。
Ctrl+F10
用于快速查看表达式等的值,对应于Debug菜单中的QuickWatch命令。
Shift+F9
用于显示Watch窗口查看变量和表达式的值
Alt+3
用于打开和隐藏Local窗口,以查看当前框架中每个程序的变量值。
Alt+4
用于显示Registers窗口
Alt+5
用于打开和隐藏Memory窗口,显示机器中指定地址以及内存使用情况
Alt+6
用于打开和隐藏CallStack窗口,显示当前执行线程中所有活动的程序及其堆栈
Alt+7
用于显示和隐藏Disassembly窗口
Alt+8
此外,表2-1中最后六个命令也可以在View菜单的DebugWindows子菜单中找到。
2.1.2启用EditandContinue特性
使用EditandContinue特性,就可以在不中断调试过程的条件下,改变源代码并将这些代码应用到程序中。
如果没有使用EditandContinue特性,要想改变并应用源代码,只有中断调试过程,然后手工重新编译程序。
下面我们就看看如何启用EditandContinue特性。
1.单击Tools菜单,从中选择Options选项,随后屏幕上就会出现如图2-12所示的界面。
图2-12Options对话框
2.在图2-12所示Options对话框中,选择Debug选项卡,确保该选项卡中启用了DebugcommandsinvokeEditandContinue选项,然后单击OK按钮关闭Options对话框。
3.单击Project菜单,选择其中的Settings选项,屏幕上就会出现如图2-13所示的对话框。
图2-13ProjectSettings对话框
4.在图2-13所示的ProjectSettings对话框中,选择C/C++选项卡,并将DebugInfo下拉列表框设置成ProgramDeatbaseforEditandContinue。
值得注意的是,修改代码后,在使用EditandContinue特性调试程序之前,需要重新编译项目,如果没有编译就进行调试,系统会提示你重新编译应用程序。
此外,EditandContinue特性不能用于编辑下列内容:
Ø头文件
ØC++类定义
Ø函数原型
Ø全局/静态代码
2.2错误和异常处理
在本节中,我们将介绍一些有效的错误和异常处理方法,通常的做法是将错误处理代码内置在函数中,以确保程序的顺利执行,一旦发生严重错误,错误处理代码就会终止应用程序的执行,从而避免系统的崩溃。
2.2.1编写与操作系统相适应的错误处理函数
几乎所有的函数,包括MicrosoftWin32和MFC例程,都有可能发生失效,这对于多任务环境来说,比如MicrosoftWindows或WindowsNT系统,应用程序共享有限的系统资源,就更为常见。
因此应该根据操作系统的特性,编写与之相适应的程序。
当某个函数发生失效时,查看该函数的返回值,有时就可以知道错误发生在什么地方。
许多MFC函数用特殊的返回值揭示该函数中存在错误。
因此,在你自己编写程序时,就应该注意也要实现这一功能。
一、报告错误
通常来说,有两种方法报告某个函数存在错误:
Ø函数的返回值
一般来说,FALSE、NULL、0xFFFFFFFF和-1用于揭示函数发生失效。
下面的这段代码就是一个有关揭示函数是否失效的例子:
intCMyView:
:
GetLastWord()
{
…
if((m_nWordCount return–1 … } Ø设置全局错误代码 当发生错误时,设置一个全局错误代码揭示发生的错误类型,一般是调用SetLastError函数设置全局错误代码。 值得注意的是,当在程序中添加错误处理代码时,应该考虑错误检测和程序执行速度之间的平衡关系。 二、处理错误 当调用的函数报告发生错误时,通常是通过编写代码处理这些错误,编写的代码将改变程序的运行。 检测错误的方式取决于函数报告错误的方式。 一般存在下面这两种情况: 一是如果函数具有返回值,可以查看该函数的返回值。 下面的这个例子给出的是如何根据函数的返回值决定接下来执行什么操作。 ... intb=pView.GetLastWord(); if(b==-1) m_ID=ProcessEmptyDocument(); else m_ID=ProcessDocument(); ... return; 另一种情况就是如果函数中设置一个全局错误代码,可以调用GetLastError函数查看是否发生了错误。 2.2.2异常处理 所谓异常就是指非正常的,通常是意想不到的事件,这些事件会改变程序的正常进程,往往需要操作系统进行特殊处理。 一般牵涉硬件和软件两个方面。 访问损坏的内存地址和发生被0除的情况都是硬件异常的例子。 传递无效的参数或内存不足是软件异常的例子。 通常是使用特殊的C++异常处理句法对这些异常进行处理。 在进行异常处理时,操作系统和进程协调起来,一起处理异常。 当出现异常时,操作系统首先会寻找一个合适的处理程序,接着将控件传递到这个处理程序,以解决异常或者终止程序的执行。 如果没有找到合适的处理程序,就会调用一个预先定义的terminate函数,该函数的默认操作就是放弃正在进行的操作。 当然,也可以使用set_terminate函数设置自己的终止方式。 一、C++异常处理方法。 对于C++和基于MFC的应用程序来讲,C++异常处理是一种非常不错的方法,其代码包含三部分: try程序块、throw语句和catch程序块。 下面这个例子给出的就是一段C++异常处理代码,在这个例子中,try程序块编写头文件,catch程序块处理指定的文件异常,而throw宏命令处理其他的异常。 try { //Writethefileheader file.Write((LPSTR)&bmfHdr,sizeof(BITMAPFILEHEADER)); // //WritetheDIBheaderandthebits file.WriteHuge(lpBI,dwDIBSize); } catch(CFileException*e) { : : GlobalUnlock((HGLOBAL)hDib); throw; } : : GlobalUnlock((HGLOBAL)hDib); returnTRUE; 此外,为了提高文档以及软件的质量,如果希望某个函数具有抛出异常的功能,应该在程序代码中说明,下面我们以CPen指令为例进行说明: CPen(intnPenStyle,intnWidth,COLORREFcrColor) throw(CresourceException); 这个例子说明将抛出CResourceException异常类。 二、异常处理过程 当出现异常时,系统是遵循一定的路径处理该异常的,在图2-14所示界面中,给出了异常处理流程。 图2-14异常处理流程 三、MFC异常类 当在基于MFC的应用程序中使用C++异常时,编写异常处理程序常要用到CException及其延伸的对象,这些对象可以被MFC框架或应用程序抛出。 为了扩展异常结构,有时还需要从提供的异常类中产生新的异常类。 MFC提供表2-2中所示的CException扩展异常类。 表2-2扩展异常类 异常类 含义 抛出者 CMemoryException 内存不足 new操作符 CFileException 文件异常 CFile函数 CArchiveException 归档/序列化异常 CArchive函数 异常类 含义 抛出者 CNotSupportedException 对不支持服务要求的响应 代表不支持服务要求的任何函数 CResouceException Windows资源分配异常 需要Windows资源的任何函数 CDBException ODBC数据库异常 ODBC数据库类的成员函数 异常类 含义 抛出者 CDaoException DAO数据库异常 DAO数据库类的成员函数 COleException OLE异常 执行OLE操作的成员函数 COleDispatchException OLE分发异常 执行与OLE自动过程相关操作的函数 CUserException 首先用消息框警告用户然后抛出CException的异常 执行有可能失败的操作的函数 CInternetException 网络异常 导致网络操作失效的任何一个函数 2.3实例一: EditandContinue特性的使用 在本例中,我们将介绍如何在调试过程中使用EditandContinue特性。 启用该特性的步骤请参看2.1.2小节,然后单击Build菜单,从中选择RebuildAll命令,接着执行Build菜单中的ExecuteMyFirst.exe命令,就会出现如图2-15所示的界面,在这个界面中,还给出了通过移动鼠标绘制的图形。 图2-15生成的界面 接下来我们给出使用该特性的步骤: 1.在MyFirstView.cpp程序中的OnLButtonUp函数中,在CEditView: : OnLButtonUp(nFlags,point);语句处单击鼠标右键,屏幕上就会出现如图2-16所示的菜单。 2.接着选择图2-16所示菜单中的Insert/RemoveBreakpoint选项,在该语句处添加一个断点。 执行Go调试命令。 3.然后移到OnMouseMove函数处,将MoveTo函数中的两个参数修改成(startpt.y,startpt.x)。 删除上面设置的断点。 图2-16右键菜单 4.接着执行Build菜单中StartDebug子菜单中的Go命令。 屏幕上随后就会出现如图2-17所示的对话框。 图2-17编译提示对话框 5.图2-17所示的对话框提示你修改代码后,还没有编译,询问你是否要编译。 单击是(Y)按钮进行编译。 6.随后屏幕上出现与图2-15类似的对话框,不同的是在该界面中移动鼠标时,会得到你意想不到的图形,如图2-18所示,鼠标移动的轨迹是该图形右上方的边界线。 图2-18修改代码后移动鼠标得到的图形 2.4实例二: 异常处理技巧 在本实例中,我们将处理由CFileException抛出的异常,在这个过程中,需要向应用程序添加异常处理代码。 由于在这个例子中要创建一个双窗口对话框,因此我们首先介绍双窗口对话框的生成,然后在介绍异常处理方法。 2.4.1创建文件打开对话框 下面我们一起来创建一个文件打开对话框。 1.利用创建向导创建一个名为Diff的工作空间,并在创建向导第六步界面中的Baseclass下拉列表框中选择CRichEditView。 2.在工作空间中选择ResourceView选项卡,单击Dialog文件夹前面的加号,出现一个IDD_ABOUTDIALOG图标。 3.右击该图标,从弹出菜单中选择InsertDialog命令,就会出现一个IDD_DIALOG1的图标,该图标用于生成一个文件打开对话框。 4.将光标移到IDD_DIALOG1的图标上,单击鼠标右键,从弹出菜单中选择Properties选项,屏幕上出现如图2-19所示的对话框。 图2-19对话框的属性对话框 5.图2-19所示对话框中的ID下拉列表框用于修改工作空间中对话框图标的名称,在这里我们键入IDD_OPENFILES;Language下拉列表框用于选择所用语言,本例中选择English(U.S.)。 6.接着双击IDD_OPENFILES的图标,在编辑窗口中就会出现如图2-20所示的对话框界面。 图2-20对话框界面 7.在这里我们要制作一个文件打开的对话框,需要对上面这个文件打开对话框界面进行修改。 选择图2-20中的OK按钮和Cancel按钮,将它们拖动到对话框的底部并摆放整齐。 8.单击编辑窗口右边的控件工具栏中的按钮图标,在对话框上放置两个按钮,接着右击放置好的一个按钮,从弹出菜单中选择Properties选项,出现与图2-19类似的属性对话框。 9.在属性对话框中,将Caption编辑框中的内容修改为&Browse,ID编辑框设置成IDC_BUTTON_FILE1_BROWSE,你就会发现原来的Button1按钮变成了Browse按钮。 10.按照同样的方法将Button2按钮修改成Browse按钮,值得注意的是将ID编辑框设置成IDC_BUTTON_FILE2_BROWSE。 调整图2-20所示对话框界面的大小并将修改后的两个按钮移动到图2-21所示的位置。 图2-21修改后的对话框界面 11.单击右边控件工具栏中ab|编辑框按钮,接着在图2-21所示对话框界面上两个B
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第二 调试 错误 处理 技巧