Delphi“for ... to”语句从结束值开始运行 [英] Delphi "for ... to" statement runs from end value to start value

查看:154
本文介绍了Delphi“for ... to”语句从结束值开始运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  procedure TForm1.Button1Click (发信人:TObject); 
var
a:数组[0..255]的整数;
i:整数;
k,q:整数;
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只在本地声明,没有全局变量。
为什么会发生这种情况?这是正常的行为吗?

解决方案

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

在你的 Pascal 代码中,整数 I 有两个(实际上是三个)目的。首先,它是循环控制变量(或循环计数器),即它控制循环运行的次数。其次,它作为数组 a 的索引。而在第一个循环中,它也作为分配给数组元素的值。编译为机器码时,这些角色由不同的寄存器处理。如果在编译器设置中设置了优化,那么编译器会创建一个代码,将控制变量从开始值向下递减到零,如果可以的话,不用改变最终结果。这样做,因为可以避免与非零值的比较,从而更快。



在下面的 first loop 的反汇编中, ,您可以看到变量 I 的角色被处理为:


  • 注册 eax 作为循环控制变量和值被分配给数组元素

  • 寄存器 edx 指向数组元素(每增加4
    (字节))


    反汇编:

      Unit25.pas.34:for I:= 0 to 255 do 
    005DB695 33C0 XOR EAX,EAX //初始化
    005DB697 8D9500FCFFFF LEA EDX,[ebp- 00000400 $]
    Unit25.pas.36:A [1]:= I;
    005DB69D 8902 mov [edx],eax //赋值赋值
    Unit25.pas.37:end;
    005DB69F 40 INC EAX //为下一回合
    005DB6A0 83C204准备添加EDX,$ 04 //同一
    Unit25.pas.34:因为我:= 0到255做
    005DB6A3 3D00010000 CMP EAX,带环$ b $的b端005DB6A8 75F3 JNZ $ 005db69d //如果不是$ 00000100 //比较,运行下一回合

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



    在反编译 second loop 除了 I 未分配给元素外, I 与第一个循环的处理类似。因此,循环控制只作为一个循环计数器,可以向下运行。


    • 注册 eax 是循环控制变量
    • 注册 edx 是指向数组元素的指针(每增加4
      (字节)转)


      反汇编:

        Unit25.pas.39:对于I:= 0至255做
      005DB6AA B800010000 MOV EAX,$ 00000100 //初始化环路计数器
      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 //准备下一轮
      Unit25.pas.39:for I:= 0 to 255 do
      005DB6BC 48 dec eax //递减循环计数器,包括内部函数与0 $ b $比较005DB6BD 75F6 jnz $ 005db6b5 // jnz =如果不是零跳转

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



      在Delphi XE7中,在Watches窗口中,变量 I 在第一个循环中显示为递增值,而在第二个循环作为 E2171变量'i'在这里由于优化而无法访问。在早期的版本中,我记得它正在显示递减的值,我相信你会看到。


      I'm writing a simple app in Embarcadero Delphi 2010. A simple code with two cycles:

      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;
      

      According to Watch List, in second cycle variable "i" starts from value 256 and going to 0 (256, 255, 254, ..., 0), but array's elements is correct (0, 1, 2, 3, ...). Variable "i" declared only locally, no global variables. Why does this happens? Is it normal behaviour?

      解决方案

      The short answer is because of compiler optimization. The long answer is:

      In your Pascal code, the integer I has two (actually three) purposes. First, it is the loops control variable (or loop counter), that is, it controls how many times the loop is run. Secondly, it acts as index to the array a. And in the first loop it also acts as the value assigned to the array elements. When compiled to machine code, these roles are handled by different registers.

      If optimization is set in compiler settings, the compiler creates code that decrements the control variable from a start value down towards zero, if it can do so, without changing the end result. This it does, because a comparison against a non-zero value can be avoided, thus being faster.

      In following disassembly of the first loop, you can see that the roles of variable I are handled as:

      • Register eax acts as loop control variable and value to be assigned to array elements
      • Register edx is pointer to array element (incremented with 4 (bytes) per turn)

      disassembly:

      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
      

      Since eax has two roles, it must count upward. Note that it requires three commands for each loop to manage the loop counting: inc eax, cmp eax, $00000100 and jnz $005db69d.

      In the disassembly of the second loop, the roles of variable I are handled similarily as in the first loop, except I is not assigned to the elements. Therefore the loop control only acts as a loop counter and can be run downward.

      • Register eax is loop control variable
      • Register edx is pointer to array element (incremented with 4 (bytes) per turn)

      disassembly:

      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
      

      Note that in this case only two commands are needed to manage loop counting: dec eax and jnz $005db6b5.

      In Delphi XE7, in the Watches window, variable I is shown during the first loop as incrementing values but during the second loop as E2171 Variable 'i' inaccessible here due to optimization. In earlier versions I recall it was showing decrementing values which I believe you see.

      这篇关于Delphi“for ... to”语句从结束值开始运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆