La risposta breve è a causa di ottimizzazione del compilatore. La risposta lunga è:
Nel codice Pascal
, il numero intero I
ha due (in realtà tre) scopi. Innanzitutto, sono i loop variabile di controllo (o contatore di loop), ovvero controlla quante volte viene eseguito il ciclo. In secondo luogo, funge da indice per l'array a
. E nel primo ciclo funge anche da valore assegnato agli elementi dell'array. Quando vengono compilati su un codice macchina, questi ruoli vengono gestiti da registri diversi.
Se l'ottimizzazione è impostata nelle impostazioni del compilatore, il compilatore crea un codice che decrementa la variabile di controllo da un valore iniziale basso a zero, se è possibile farlo, senza modificare il risultato finale. Questo lo fa, perché un confronto con un valore diverso da zero può essere evitato, quindi essere più veloce.
Seguendo lo smontaggio del primo ciclo, si può vedere che i ruoli delle variabili I
sono gestite come:
- Register
eax
agisce come variabile di controllo valoreed essere assegnate a matrice elementi
- Il registro
edx
è puntatore all'elemento matrice (incrementato con 4 (byte) per turno)
smontaggio:
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
Da eax
ha due ruoli, essa deve contare verso l'alto.Si noti che per gestire il conteggio del ciclo sono necessari tre comandi per ciascun ciclo: inc eax
, cmp eax, $00000100
e jnz $005db69d
.
Nel smontaggio del secondo anello, i ruoli delle variabili I
vengono gestiti in modo simile come nel primo ciclo, tranne I
non è assegnato agli elementi. Pertanto il controllo del loop agisce solo come un contatore di loop e può essere eseguito verso il basso.
- Register
eax
è controllo ad anello variabile
- Register
edx
è puntatore all'elemento array (incrementato con 4 (bytes) per turno)
smontaggio:
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
noti che in questo caso sono necessari solo due comandi per gestire il conteggio dei cicli: dec eax
e jnz $005db6b5
.
In Delphi XE7, nella finestra Orologi, la variabile I
viene visualizzata durante il primo ciclo come valori di incremento ma durante il secondo ciclo come E2171 Variable 'i' inaccessible here due to optimization
. Nelle versioni precedenti ricordo che mostrava valori decrescenti che credo tu veda.
Nota a margine: non utilizzare * numeri magici *: 'per i: = 0 a Length (a) do' –
Solo uno strano test di comportamento, non un codice di produzione. Anche la lunghezza (a) funziona in questo modo. –
Un po 'di googling dovrebbe aver dato un sacco di hit che ti dicono che è un'ottimizzazione del compilatore Delphi che viene applicato solo se non altera il significato del tuo codice. –