德尔福" for ... to"语句从结束值到起始值运行

时间:2016-02-18 07:46:51

标签: delphi for-loop

我在Embarcadero Delphi 2010中编写了一个简单的应用程序。一个包含两个周期的简单代码:

procedure TForm1.Button1Click(Sender: TObject);
var
a:array [0..255] of integer;
i:integer;
k,q:integer;
begin
k:=0;
for I := 0 to 255 do
 begin
    a[i]:=i;
 end;

for I := 0 to 255 do
 begin
    q:= a[i];
    k:=k+q;
 end;
Label1.Caption:=inttostr(k);
end;

根据观察清单,在第二个周期变量" i"从值256开始并转到0(256,255,254,...,0),但数组的元素是正确的(0,1,2,3,...)。变量" i"仅在本地声明,没有全局变量。 为什么会这样?这是正常的行为吗?

2 个答案:

答案 0 :(得分:13)

简短的回答是因为编译器优化。答案很长:

Pascal代码中,整数I有两个(实际上是三个)目的。首先,它是循环控制变量(或循环计数器),也就是说,它控制循环运行的次数。其次,它充当数组a的索引。在第一个循环中,它还充当分配给数组元素的值。编译为机器代码时,这些角色由不同的寄存器处理。

如果在编译器设置中设置了优化,则编译器会创建将控制变量从起始值向下递减为零的代码,如果可以,则为,而不更改最终结果。这样做,因为可以避免与非零值的比较,从而更快。

第一个循环的反汇编中,您可以看到变量I的角色被处理为:

  • 注册eax充当循环控制变量和值 分配给数组元素
  • 寄存器edx是指向数组元素的指针(以4递增) 每回合(字节))

拆卸:

Unit25.pas.34: for I := 0 to 255 do
005DB695 33C0             xor eax,eax             // init
005DB697 8D9500FCFFFF     lea edx,[ebp-$00000400]
Unit25.pas.36: a[i]:=i;
005DB69D 8902             mov [edx],eax           // value assignment
Unit25.pas.37: end;
005DB69F 40               inc eax                 // prepare for next turn
005DB6A0 83C204           add edx,$04             // same
Unit25.pas.34: for I := 0 to 255 do
005DB6A3 3D00010000       cmp eax,$00000100       // comparison with end of loop
005DB6A8 75F3             jnz $005db69d           // if not, run next turn

由于eax有两个角色,因此必须向上计数。请注意,每个循环需要三个命令来管理循环计数:inc eaxcmp eax, $00000100jnz $005db69d

第二个循环的反汇编中,变量I的角色与第一个循环中的角色类似,除了I未分配给元素。因此,循环控制仅用作循环计数器,可以向下运行。

  • 注册eax是循环控制变量
  • 寄存器edx是指向数组元素的指针(以4递增) 每回合(字节))

拆卸:

Unit25.pas.39: for I := 0 to 255 do
005DB6AA B800010000       mov eax,$00000100       // init loop counter
005DB6AF 8D9500FCFFFF     lea edx,[ebp-$00000400]
Unit25.pas.41: q:= a[i];
005DB6B5 8B0A             mov ecx,[edx]
Unit25.pas.42: k:=k+q;
005DB6B7 03D9             add ebx,ecx
Unit25.pas.43: end;
005DB6B9 83C204           add edx,$04    // prepare for next turn
Unit25.pas.39: for I := 0 to 255 do
005DB6BC 48               dec eax        // decrement loop counter, includes intrinsic comparison with 0
005DB6BD 75F6             jnz $005db6b5  // jnz = jump if not zero

请注意,在这种情况下,只需要两个命令来管理循环计数:dec eaxjnz $005db6b5

在Delphi XE7中,在Watches窗口中,变量I在第一个循环期间显示为递增值,但在第二个循环期间显示为E2171 Variable 'i' inaccessible here due to optimization。在早期版本中,我记得它显示了我相信你看到的递减值。

答案 1 :(得分:8)

我已经复制了您的确切代码,当我运行变量" i"通常在两个循环中计数。你一步一步地跑了第二个周期吗? "我"因为第一个循环,第二个循环开始时真的是256,但是一旦第二个循环开始,#34; i"变为0,它通常计为255.

我不知道它是如何或为什么从256到0?

<强>更新 我甚至没有想到这一点,但是我相信你的解释:http://www.delphigroups.info/2/45/418603.html

  

&#34;这是一个编译器优化 - 你没有使用&#34;我&#34;在你的循环中   因此编译器想到了一种更好的计数方法。你的循环计数   仍然准确......&#34;