Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
554 views
in Technique[技术] by (71.8m points)

for loop - Delphi "for ... to" statement runs from end value to start value

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...