gpt4 book ai didi

delphi - 局部变量和 TPair 数组 - 内存分配的奇怪行为

转载 作者:行者123 更新时间:2023-12-03 14:41:32 25 4
gpt4 key购买 nike

我在 delphi xe5 update 2 中编译了以下代码示例。

procedure TForm1.FormCreate(Sender: TObject);
var i,t:Integer;
buf: array [0..20] of TPair<Integer,Integer>;
begin
t := 0;
for i := Low(buf) to High(buf) do begin
ShowMessage(
Format(
'Pointer to i = %p;'#$d#$a+
'Pointer to buf[%d].Key = %p;'#$d#$a+
'Pointer to buf[%d].Value = %p;'#$d#$a+
'Pointer to t = %p',
[@i, i, @(buf[i].Key), i, @(buf[i].Value), @t]
)
);
buf[i].Key := 0;
buf[i].Value := 0;
t := t + 1;
end;
end;

如果我运行它,它会显示变量的地址。变量it的地址在buf内存范围内!
i达到3时,赋值buf[i].Value := 0;覆盖i的前3个字节和的最后一个字节>t。这会导致无限循环,因为 i 在达到 3 时始终重置为 0
如果我自己用 SetLength(buf,20); 分配内存,一切都很好。

图片说明了我的意思。

Output, Memory Adresses

我的设置:

  • Windows 7 64 位
  • 德尔福 XE 5 更新 2
  • 调试配置 32 位

很奇怪,不是吗?
有人可以复制它吗?
这是delphi编译器中的一个错误吗?

谢谢。

编辑:
这是相同的示例,但也许更好地理解我的意思: memory areas

顺便说一句:抱歉我的英语不好;)

最佳答案

这绝对看起来像一个编译器错误。它只影响 TPair 的数组分配在堆栈上。例如,这个编译并运行良好:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
Generics.Collections;

var i:Integer;
buf: array [0..20] of TPair<Integer,Integer>;
begin
for i := Low(buf) to High(buf) do begin
buf[i].Key := 0;
buf[i].Value := 0;
end;
end.

然而,这表明了错误:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
Generics.Collections;

procedure DoSomething;
var i:Integer;
buf: array [0..20] of TPair<Integer,Integer>;
begin
for i := Low(buf) to High(buf) do begin
buf[i].Key := 0;
buf[i].Value := 0;
end;
end;

begin
DoSomething;
end.

编译器似乎错误地计算了 TPair<Integer,Integer> 的大小。编译后的程序集显示的序言如下:

Project1.dpr.14: begin
00445C50 55 push ebp
00445C51 8BEC mov ebp,esp
00445C53 83C4E4 add esp,-$1c //*** Allocate only 28 bytes (7words)
Project1.dpr.15: for i := Low(buf) to High(buf) do begin
00445C56 33C0 xor eax,eax
00445C58 8945FC mov [ebp-$04],eax
Project1.dpr.16: buf[i].Key := 0;
00445C5B 8B45FC mov eax,[ebp-$04]
00445C5E 33D2 xor edx,edx
00445C60 8954C5E7 mov [ebp+eax*8-$19],edx
Project1.dpr.17: buf[i].Value := 0;
00445C64 8B45FC mov eax,[ebp-$04]
00445C67 33D2 xor edx,edx
00445C69 8954C5EB mov [ebp+eax*8-$15],edx
Project1.dpr.18: end;
00445C6D FF45FC inc dword ptr [ebp-$04]
Project1.dpr.15: for i := Low(buf) to High(buf) do begin
00445C70 837DFC15 cmp dword ptr [ebp-$04],$15
00445C74 75E5 jnz $00445c5b
Project1.dpr.19: end;
00445C76 8BE5 mov esp,ebp
00445C78 5D pop ebp
00445C79 C3 ret
00445C7A 8BC0 mov eax,eax

编译器仅在堆栈上分配了 7 个双字。第一个是整数 i ,只留下 6 个双字分配给 TPair数组,这是不够的( SizeOf(TPair<integer,integer>) 等于 8 -> 两个双字)。在第三次迭代中,mov [ebp+eax*8-$15],edx (即: buf[2].Value )运行到 i 的堆栈位置并将其值设置为零。

您可以通过在堆栈上强制提供足够的空间来演示工作程序:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
Generics.Collections;


procedure DoSomething;
var i:Integer;
fixalloc : array[0..36] of Integer; // dummy variable
// allocating enough space for
// TPair array
buf: array [0..20] of TPair<Integer,Integer>;
begin
for i := Low(buf) to High(buf) do begin
buf[i].Key := i;
buf[i].Value := i;
end;
end;

begin
DoSomething;
end.

这已在 XE2 中进行了测试,但如果您也发现了该问题,则似乎至少在 XE5 中仍然存在。

关于delphi - 局部变量和 TPair<Int,Int> 数组 - 内存分配的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25262314/

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