The Delphi "for ... to" statement works from the end value to the start value

I am writing a simple application in Embarcadero Delphi 2010. Simple two-loop code:

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 the observation list, in the second cycle, the variable "i" begins with the value 256 and goes to 0 (256, 255, 254, ..., 0), but the elements of the array are correct (0, 1, 2, 3, ...) . The variable "i" is declared only locally, without global variables. Why is this happening? Is this normal behavior?

+7
for-loop delphi
source share
2 answers

The short answer is due to compiler optimization. Long answer:

In Pascal code, the integer I has two (actually three) goals. Firstly, it is the control variable of the cycle (or cycle counter), that is, it determines how many times the cycle starts. Secondly, it acts as an index of array a . And in the first loop, it also acts as the value assigned to the elements of the array. When compiled into machine code, these roles are processed by different registers.

If optimization is specified in the compiler settings, the compiler creates code that reduces the control variable from the initial value to zero, if possible, without changing the final result. This happens because comparison with a non-zero value can be avoided, thereby accelerating.

The next time you disassemble the first loop, you will see that the roles of variable I treated as:

  • The eax register acts as a loop control variable, and the value is assigned to array elements
  • Register edx - pointer to an array element (with the addition of 4 (bytes) per move)

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 up. Note that to control the loop, three commands are required for each loop: inc eax , cmp eax, $00000100 and jnz $005db69d .

When disassembling the second cycle, the roles of the variable I processed similarly in the first cycle, except that I not assigned to the elements. Therefore, loop control only works as a loop counter and can be started down.

  • Register eax - loop control variable
  • Register edx - pointer to an array element (with the addition of 4 (bytes) per move)

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 control the loop counts: dec eax and jnz $005db6b5 .

In Delphi XE7, in the Clock window, the variable I displayed during the first cycle as increasing values, but in the second cycle E2171 Variable 'i' inaccessible here due to optimization . In earlier versions, I remember that it showed decrement values, which I think you see.

+13
source share

I copied your exact code, and when I ran it, the variable "i" is usually considered as for loops. Did you go through the second cycle step by step? "I" is really 256 at the beginning of the second cycle because of the first, but as soon as the second cycle begins, "i" becomes 0, and it is usually considered 255.

I donโ€™t see how and why it will count from 256 to 0?

UPDATE: I didnโ€™t even think about it, but I believe your explanation: http://www.delphigroups.info/2/45/418603.html

"This is a compiler optimization - you are not using the self inside your loop, so the compiler was thinking of a better way to count. The number of loops will still be accurate ..."

+8
source share

All Articles