您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 企业财务 > 第十二章异常处理与程序调试(一)
在应用程序开发中如何检测、处理程序的运行错误是一个很重要的问题。在Delphi的集成开发环境(IDE)中提供了一个完善的内置调试器,可以帮助你发现大部分程序错误。但并不是所有的错误都可以被发现,而且当程序涉及到与外设的数据交换或操作外设,如要求用户输入、读写磁盘等时,错误的发生是程序无法控制的,如输入非法字符、磁盘不能读写等。这些情况不仅会导致应用程序异常中止而且可能引起系统的崩溃。针对这些问题,Delphi同时提供了一套强大的异常处理机制。巧妙地利用它,可以使你的程序更为强健,使用更为友好。虽然Delphi为应用程序提供了一套缺省的自动异常处理机制,即当前模块发生错误后退出当前模块并给出错误信息,而并不立即引起应用程序的中止。但当应用程序执行的过程性很强时,仅仅利用这种方法是不够的,而且很容易导致程序执行的不可预测性。12.1Delphi异常处理机制与异常类Delphi异常处理机制建立在保护块(ProtectedBlocks)的概念上。所谓保护块是用保留字try和end封装的一段代码。保护块的作用是当应用程序发生错误时自动创建一个相应的异常类(Exception)。程序可以捕获并处理这个异常类,以确保程序的正常结束以及资源的释放和数据不受破坏。如果程序不进行处理,则系统会自动提供一个消息框。异常类是Delphi异常处理机制的核心,也是Delphi异常处理的主要特色。下面我们对异常类的概念和体系进行详细的介绍。Delphi提供的所有异常类都是类Exception的子类。用户也可以从Exception派生一个自定义的异常类。Exception类的定义如下,对于不常用的成员没有列出。{SysUtils单元中}Exception=class(TObject)privateFMessage:PString;FHelpContext:Longint;functionGetMessage:String;procedureSetMessage(constValue:String);publicconstructorCreate(constMsg:String);constructorCreateFmt(constMsg:String;constArgs:arrayofconst);...destructorDestroy;override;propertyHelpContext:LongintpropertyMessage:String;propertyMessagePtr:PString;end;Exception的一系列构造函数中最重要的参数是显示的错误信息。而数据成员中最重要的也是可被引用的消息字符串(message,messagePtr)。这些信息分别对自定义一个异常类和处理一个异常类有重要作用。Delphi提供了一个很庞大的异常类体系,这些异常类几乎涉及到编程的各个方面。从大的方面我们可以把异常类分为运行时间库异常、对象异常、部件异常三类。下面我们分别进行介绍。12.1.1运行时间库异常类(RTLException)运行时间库异常可以分为七类,它们都定义在SysUtils库单元中。12.1.1.1I/O异常I/O异常类EInOutError是在程序运行中试图对文件或外设进行操作失败后产生的,它从Exception派生后增加了一个公有数据成员ErrorCode,用于保存所发生错误的代码。这一成员可用于在发生I/O异常后针对不同情况采取不同的对策。当设置编译指示{$I-}时,不产生I/O异常类而是把错误代码返回到预定义变量IOResult中。12.1.1.2堆异常堆异常是在动态内存分配中产生的,包括两个类EOutOfMemory和EInvalidPointer。表12.1堆异常类及其产生原因━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━异常类引发原因─────────────────────────────────EOutOfMemory没有足够的空间用于满足所要求的内存分配EInvalidPointer非法指针。一般是由于程序试图去释放一个业已释放的指针而引起的━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━12.1.1.3整数异常整数异常都是从一个EIntError类派生的,但程序运行中引发的总是它的子类:EDivByZero,ERangeError,EIntOverFlow。表12.2整数异常及其产生原因━━━━━━━━━━━━━━━━━━━━━异常类引发原因─────────────────────EDivByZero试图被零除ERangeError整数表达式越界EIntOverFlow整数操作溢出━━━━━━━━━━━━━━━━━━━━━━ERangeError当一个整数表达式的值超过为一个特定整数类型分配的范围时引发。比如下面一段代码将引发一个ERangeError异常。varSmallNumber:ShortInt;X,Y:Integer;beginX:=100;Y:=75;SmallNumber:=X*Y;end;特定整数类型包括ShortInt、Byte以及与整数兼容的枚举类型、布尔类型等。例如:typeTHazard=(Safety,Marginal,Critical,Catastrophic);varHaz:THazard;Item:Integer;beginItem:=4;Haz:=THazard(Item);end;由于枚举数越界而引发一个ERangeError异常。数组元素越界也会引发一个ERangeError异常,如:varValues:array[1..10]ofInteger;i:Integer;beginfori:=1to11doValues[i]:=i;end;ERangeError异常只有当类型检查打开时才会引发。这可以在代码中包含{$R+}编译指示或设置IDEOption|Project的Range_CheckingOption选择框。EIntOverFlow异常类在Integer、Word、Longint三种整数类型越界时引发。如:varI:Integer;a,b,c:Word;begina:=10;b:=20;c:=1;forI:=0to100dobeginc:=a*b*c;end;end;引发一个EIntOverFlow异常。EIntOverFlow异常类只有在编译选择框Option|Project|Over_Flow_CheckOption选中时才产生。当关闭溢出检查,则溢出后变量保留该类整数的最大范围值。整数类型的范围如下表。表12.3整数类型的范围━━━━━━━━━━━━━━━━━━━━━━━━━━━类型范围格式───────────────────────────Shortint-128..127有符号8位Integer-32768..32767有符号16位Longint-2147483648..2147483647有符号32位Byte0..255无符号8位Word0..65535无符号16位━━━━━━━━━━━━━━━━━━━━━━━━━━━12.1.1.4浮点异常浮点异常是在进行实数操作时产生的,它们都从一个EMathError类派生,但与整数异常相同,程序运行中引发的总是它的子类EInvalidOp、EZeroDivide、EOverFlow、EUnderFlow。表12.4浮点异常类及其引发原因━━━━━━━━━━━━━━━━━━━━━━━━异常类引发原因────────────────────────EInvalidOp处理器碰到一个未定义的指令EZeroDivide试图被零除EOverFlow浮点上溢EUnderFlow浮点下溢━━━━━━━━━━━━━━━━━━━━━━━━EInvalidOp最常见的引发原因是没有协处理器的机器遇到一个协处理器指令。由于在缺省情况下Delphi总是把浮点运算编译为协处理器指令,因而在386以下微机上常常会碰到这个错误。此时只需要在单元的接口部分设置全局编译指示{$N-},选择利用运行时间库进行浮点运算,问题就可以解决了。各种类型的浮点数(Real、Single、Double、Extended)越界引起同样的溢出异常。这同整数异常类是不同的。12.1.1.5类型匹配异常类型匹配异常EInvalidCast当试图用As操作符把一个对象与另一类对象匹配失败后引发。12.1.1.6类型转换异常类型转换异常EConvertError当试图用转换函数把数据从一种形式转换为另一种形式时引发,特别是当把一个字符串转换为数值时引发。下面程序中的两条执行语句都将引发一个EConvertError异常。varrl:Real;int:Integer;beginrl:=StrToFloat('$140.48');int:=StrToInt('1,402');end;要注意并不是所有的类型转换函数都会引发EConvertError异常。比如函数Val当它无法完成字符串到数值的转换时只把错误代码返回。利用这一点我们在(6.2)节中实现了输入的类型和范围检查。12.1.1.7硬件异常硬件异常发生的情况有两种:或者是处理器检测到一个它不能处理的错误,或者是程序产生一个中断试图中止程序的执行。硬件异常不能编译进动态链接库(DLLs)中,而只能在标准的应用中使用。硬件异常都是EProcessor异常类的子类。但运行时间并不会引发一个EProcessor异常。表12.5硬件异常类及其产生原因━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━异常类引发原因─────────────────────────────────Efault基本异常类。是其它异常类的父类EGPFault一般保护错。通常由一个未初始化的指针或对象引起EStackFault非法访问处理器的栈段EPageFaultWindows内存管理器不能正确使用交换文件EInvalidOpCode处理器碰到一个未定义的指令。这通常意味着处理器试图去操作非法数据或未初始化的内存EBreakPoint应用程序产生一个断点中断ESingleStep应用程序产生一个单步中断━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━EFault、EGPFault往往意味着致命的错误。而EBreakPoint、ESingleStep被DelphiIDE的内置调试器处理。事实上前边的五种硬件异常的响应和处理对开发者来说都是十分棘手的问题。12.1.2对象异常类所谓对象异常是指非部件的对象引发的异常。Delphi定义的对象异常包括流异常、打印异常、图形异常、字符串链表异常等。12.1.2.1流异常类流异常类包括EStreamError、EFCreateError、EFOpenError、EFilerError、EReadError、EWriteError、EClassNotFound。它们的结构关系如下:EStreamError|----------EFCreateError|----------EFOpenError|----------EFilerError|---------EReadError|---------EWriteError|---------EClassNotFound图12.1流异常结构图流异常在Classes库单元中定义。流异常引发的原因如表12.6。表12.6流异常类及其产生原因━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━异常类引发原因─────────────────────────────────EStreamError利用LoadFromStream方法读一个流发生错误EFCreateError创建文件时发生错误EFOpenError打开文件时发生错误EFilerError试图再次登录一个存在的对象EReadErrorReadBuffer方法不能读取特定数目的字节EWriteErrorWriteBu
本文标题:第十二章异常处理与程序调试(一)
链接地址:https://www.777doc.com/doc-2163414 .html