异常消息从何而来?

Where does exception message comes from?

当出现 EZeroDivideEOverflowEMathError... 等异常时,它们会显示一条默认消息。

例如,以下代码引发 EZeroDivide 并显示以下消息:

Floating point division by zero

procedure TForm1.Button1Click(Sender: TObject);
var
  N : Extended;
  D : Extended;
begin
  N := 100;
  D := 0;
  Caption := FloatToStr(N/D);
end;

当我 "manually" 通过代码引发 EZeroDivide 异常时,我必须将 Msg 参数传递给构造函数并将其作为 EZeroDivide 异常引发有一个空字符串消息:

procedure TForm1.Button2Click(Sender: TObject);
begin
  raise EZeroDivide.Create('');
end;

默认异常消息从何而来?

那些异常实例是由 RTL 内部生成的。问题中的具体字符串可以在SysConst.pas

resourcestring部分找到
 SZeroDivide = 'Floating point division by zero';

RTL 在内部使用 Error 方法来引发此类异常。运行时错误的完整列表在以下枚举的 System 单元中定义:

TRuntimeError = (reNone, reOutOfMemory, reInvalidPtr, reDivByZero,
  reRangeError, reIntOverflow, reInvalidOp, reZeroDivide, reOverflow,
  reUnderflow, reInvalidCast, reAccessViolation, rePrivInstruction,
  reControlBreak, reWhosebug,
  { reVar* used in Variants.pas }
  reVarTypeCast, reVarInvalidOp,
  reVarDispatch, reVarArrayCreate, reVarNotArray, reVarArrayBounds,
  reAssertionFailed,
  reExternalException, { not used here; in SysUtils }
  reIntfCastError, reSafeCallError,
  reMonitorNotLocked, reNoMonitorSupport
{$IF defined(LINUX) or defined(MACOS) or defined(ANDROID)}
  , reQuit
{$ENDIF LINUX or MACOS or ANDROID}
{$IFDEF POSIX}
  , reCodesetConversion
{$ENDIF POSIX}
  , rePlatformNotImplemented, reObjectDisposed
  );

如果您有真正的理由自己引发运行时错误,您可以通过调用来完成,例如:

 System.Error(reZeroDivide);

如果你很细心,你会注意到 ErrorSystem 单元中没有前向声明,而只存在于实现部分。通常,这会阻止您在其包含单元之外调用该方法的可见性,但 System 单元在许多方面都很特殊,并且此方法可在全球范围内访问。请注意,您还经常包含 Windows 单元,这声明了一个名为 ERROR 的常量,它通常会隐藏 System.Error,因此通常需要显式限定它的范围。