gpt4 book ai didi

Delphi调试器-发生异常时转到行

转载 作者:行者123 更新时间:2023-12-03 18:31:33 24 4
gpt4 key购买 nike

我在工作中切换到其他项目,我注意到 Delphi XE2 调试器没有显示引发异常的行。当我回到家时,我开始调查。然后我发现可以在Tools -> Options -> Debugger 选项中禁用它并检查Integrated debugging。此外,我取消选中要忽略的异常类型 列表中语言异常 下的所有内容。 通知语言异常保持选中状态。 Project -> Options -> Compiling,我在那里设置了默认值,并启用了OverflowRange cheking。我正在运行调试 构建。我清理它。

我以前没有注意到,但是现在当我调用这段代码时,Delphi 调试器不给我行:

procedure TForm1.BitBtn1Click(Sender: TObject);
var
_List: TStringList;
begin
_List := TStringList.Create;
try
Caption := _List[0]; // 'List index out of bounds (0)' here
finally
FreeAndNil(_List);
end;
end;

但这有效(提供只是为了表明调试器确实显示了某些东西的行):

{$R+} // Range check is ON
procedure TForm1.BitBtn2Click(Sender: TObject);
var
_myArray: array [1 .. 5] of string;
i: integer;
begin
for i := 0 to 5 do
begin
_myArray[i] := 'Element ' + IntToStr(i); // Range check error here
ShowMessage('myArray[' + IntToStr(i) + '] = ' + _myArray[i]);
end;
end;

这里发生了什么?如何让调试器尽可能多地显示?

谢谢。

最佳答案

我先回答这个问题。

How to make the compiler show as much as possible

编译器向您显示错误出在对 btnclick 的调用中。
诀窍是使用 F5 在 btnclick 过程的第一行放置一个断点。
然后重建(!)应用程序并再次运行。
执行将停止该断点。
使用 F8 逐步执行代码,直到出现错误。
在产生错误的行上放置一个断点F5
中止并重新运行应用程序。
当您到达第二个断点而不是按 F8 时,按 F7 进入导致错误的例程,继续按 F7/F8 直到您看到导致问题的确切原因。

为什么会这样?
编译器通过跟踪堆栈跟踪来追溯异常源。
因为在您的情况下,生成异常的代码没有堆栈跟踪(因为它不是调试代码),所以编译器无法执行此技巧,而是遵循确实具有的堆栈跟踪;它在您的代码中向上移动了一个级别并在那里标记异常。

详细看一下
你在比较苹果和橘子。

此代码(附件 A):

Caption := _List[0]; // 'List index out of bounds (0)' here

与此代码完全没有共同之处(图表 B):

_myArray: array [1 .. 5] of string;
....
_myArray[0]:= 'Hallo';

图表 A 使用了 TStringList 类的 items 属性,其定义大致如下(我稍微简化了一下,但基本原理是正确的):

type
TStringList = class(TStrings)
strict private
FList: array of string;
....
private
procedure Put(index: integer; const value: string);
function Get(index: integer): string;
published
property Items[index: integer]: string read Get write Put; default;
// ------------------------------------------------------^^^^^^^
....
end;

请注意 Items 属性末尾的 default 关键字。

这一切意味着,当您调用 _List[0] 时,您实际上是在调用 _List.Items[0],它被翻译成 Caption := _List.Getitems(0),因为属性上有 read 修饰符。
default 关键字允许您省略 .Items

Get 代码如下所示:

function TStringList.Get(Index: Integer): string;
begin
if Cardinal(Index) >= Cardinal(FCount) then
Error(@SListIndexError, Index); <<-Here is the line that generates the error*
Result := FList[Index].FString;
end;

*实际上错误是在Error例程中产生的

除非您拥有 RTL/VCL 源代码并且您正在使用调试 DCU 运行,否则您将不会在异常的确切触发器(位于 system.classes 内)单元上中断.
请注意,此错误不依赖于范围检查,它总是会触发。
因为 Delphi 没有生成错误的确切行的调试信息,所以它会退而求其次并尝试进行猜测。

精简版
stringlist 是一个伪装成数组的复杂抽象。
调用了大量代码,使得编译器难以查明错误。

在附件 B 中:

_myArray: array [1 .. 5] of string;
....
i:= 0;
_myArray[i]:= 'Hallo';

生成范围检查错误或访问冲突。
这两个错误都发生在确切的行上,允许编译器在正确的位置停止。

精简版
plain 数组是一个基本构建 block ,没有对其他地方代码的隐藏调用,这使得编译器很容易查明错误。

了解属性
类和记录属性(以及现在的类运算符)看起来像是对变量的简单赋值/操作,但实际上是对(可能是复杂的)子例程的调用。

关于Delphi调试器-发生异常时转到行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24709997/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com