网站首页/技术开发列表/内容

第12章 异常处理与程序调试(一)

技术开发2022-07-12阅读
在应用程序开发中如何检测、处理程序的运行错误是一个很重要的问题。在 Delphi 的集成开发环境( IDE )中提供了一个完善的内置调试器,可以帮助你发现大部分程序错误。但并不是所有的错误都可以被发现,而且当程序涉及到与外设的数据交换或操作外设,如要求用户输入、读写磁盘等时,错误的发生是程序无法控制的,如输入非法字符、磁盘不能读写等。这些情况不仅会导致应用程序异常中止而且可能引起系统的崩溃。针对这些问题,Delphi同时提供了一套强大的异常处理机制。巧妙地利用它,可以使你的程序更为强健,使用更为友好。
  虽然Delphi为应用程序提供了一套缺省的自动异常处理机制,即当前模块发生错误后退出当前模块并给出错误信息,而并不立即引起应用程序的中止。但当应用程序执行的过程性很强时,仅仅利用这种方法是不够的,而且很容易导致程序执行的不可预测性。 

  12.1 Delphi异常处理机制与异常类 

  Delphi异常处理机制建立在保护块(Protected Blocks)的概念上。所谓保护块是用保留字try和end封装的一段代码。保护块的作用是当应用程序发生错误时自动创建一个相应的异常类(Exception)。程序可以捕获并处理这个异常类,以确保程序的正常结束以及资源的释放和数据不受破坏。如果程序不进行处理,则系统会自动提供一个消息框。

  异常类是Delphi异常处理机制的核心,也是Delphi异常处理的主要特色。下面我们对异常类的概念和体系进行详细的介绍。

  Delphi提供的所有异常类都是类Exception的子类。用户也可以从Exception派生一个自定义的异常类。

  Exception类的定义如下,对于不常用的成员没有列出。  

  {SysUtils 单元中}

  Exception = class(TObject)

  private

  FMessage: PString;

  FHelpContext: Longint;

  function GetMessage: String;

  procedure SetMessage(const Value: String);

  public

  constructor Create(const Msg: String);

  constructor CreateFmt(const Msg: String; const Args: array of const);. . .

  destructor Destroy; override;

  property HelpContext: Longint

  property Message: String;

  property MessagePtr: PString;

  end; 

  Exception的一系列构造函数中最重要的参数是显示的错误信息。而数据成员中最重要的也是可被引用的消息字符串(message,messagePtr)。 这些信息分别对自定义一个异常类和处理一个异常类有重要作用。

  Delphi提供了一个很庞大的异常类体系,这些异常类几乎涉及到编程的各个方面。从大的方面我们可以把异常类分为运行时间库异常、对象异常、部件异常三类。下面我们分别进行介绍。 

  12.1.1 运行时间库异常类(RTL Exception) 

  运行时间库异常可以分为七类,它们都定义在SysUtils库单元中。 

  12.1.1.1 I/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异常。 

  var

  SmallNumber: ShortInt;

  X , Y: Integer;

  begin

  X := 100;

  Y := 75;

  SmallNumber := X * Y;

  end;

  特定整数类型包括ShortInt、Byte以及与整数兼容的枚举类型、布尔类型等。例如:  

  type

  THazard = ( Safety , Marginal , Critical , Catastrophic );

  var

  Haz: THazard;

  Item: Integer;

  begin

  Item:= 4;

  Haz:= THazard ( Item );

  end; 

  由于枚举数越界而引发一个ERangeError异常。

  数组元素越界也会引发一个ERangeError异常,如: 

  var

  Values: array[1..10] of Integer;

  i: Integer;

  begin

  for i := 1 to 11 do

  Values[i] := i;

  end;

  ERangeError异常只有当类型检查打开时才会引发。这可以在代码中包含{$R+} 编译指示或设置IDE Option|Project的Range_Checking Option选择框。

  EIntOverFlow异常类在Integer、Word、Longint三种整数类型越界时引发。如:

  var

  I : Integer;

  a,b,c : Word;

  begin

  a := 10;

  b := 20;

  c := 1;

  for I := 0 to 100 do

  begin

  c := a*b*c;

  end;

  end;

  引发一个EIntOverFlow异常。

  EIntOverFlow异常类只有在编译选择框Option|Project|Over_Flow_Check Option选中时才产生。当关闭溢出检查,则溢出后变量保留该类整数的最大范围值。

  整数类型的范围如下表。 

[1] [2] [3]  下一页

……

相关阅读