我有以下代码示例编译在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),@(buf[i].Value),@t] ) ); buf[i].Key := 0; buf[i].Value := 0; t := t + 1; end; end;
如果我运行它,它会显示变量的地址.
变量i和t在buf的内存范围内具有地址!
当ireaches 3时,赋值buf [i] .Value:= 0;覆盖i的前3个字节和t的最后一个字节.这导致无限循环,因为当它达到3时,我得到重置为0.
如果我用SetLength(buf,20)自己分配内存;一切安好.
我的设置:
> Windows 7 64位
> Delphi XE 5 Update 2
>调试配置32位
奇怪,不是吗?
有人可以重现吗?
是delphi编译器中的错误吗?
谢谢.
编辑:
这是同样的例子,但也许更好地了解我的意思:
和btw:对不起,我的英文不好)
解决方法
这肯定是一个编译器的bug.它只影响在堆栈上分配的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,只留下分配给TPair阵列的6个双词,这是不够的(SizeOf(TPair <整数,整数)等于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.