Link to home
Start Free TrialLog in
Avatar of ThomasReimann
ThomasReimann

asked on

Small delphi debugger problem

I have a problem with the Delphi 5 debugger.

I have a break point in a for loop that goes from 0 to 100.

the debugger shows the loop counter as 101.

what is going on?

here is a screenshot:

http://img403.imageshack.us/my.php?image=screen2dl5.png
Avatar of Geert G
Geert G
Flag of Belgium image

sometimes the debugger messes up a for loop, dunno why
the thing i get in Delphi 7 is the loop is reversed, instead of 0 to 100 it goes 100 to 0
if you really want to see if the value is wrong,
the best way is to save a message with your for variable to a log file

i use a AddToLog proc to do this

in the loop just add a line to add to the log file

AddToLog(Format('I: %d, Color: %d', [I, Colors[I]));

My 2 cents about compiler directives:
They are very easy to use, but very dangerous.
Take this situation:
You test your app (with the compiler directive on) -> works ok
Then let somebody else test it -> works ok
Then put a version into production
If you have a nightly build system which recompiles an app
without the compiler directive, it will put apps into production that are not tested !
Compiler directives can cause totally different apps !




procedure AddToLog(Msg: string);
var
  LogFile: TextFile;
  TimeStr : string;
begin
  if Profiling then 
  begin
    if LastTime <= 1 then
      LastTime := Now;
    TimeStr := Now - LastTime;
    AssignFile(LogFile, ChangeFileExt(Application.Exe, '.log'));
    try
      Append(LogFile);
    except
      Rewrite(LogFile);
    end;
    Writeln(LogFile, Msg + '|' + FloatToStr(DateTimeToFloat(TimeStr)));
    CloseFile(LogFile);
  end;
end;
 
const Profiling: Boolean = False;
 
procedure ProfilingOn;
begin
  Profiling := True;
end;
 
procedure ProfilingOff;
begin
  Profiling := False;
end;

Open in new window

Avatar of ThomasReimann
ThomasReimann

ASKER

The loop is reserved here to.

It should go from 0 to 100 (no downto!!!)

the first 3 steps shoud be:
0 1 2

the debugged shows instead:

101 100 99

if it were

100 99 98 instead it would not worry me (it may be optimization, but {$O-} before the loop does not change anything.

what worries me is the value 101. how could the debugger mess up this?
dunno, but it happens only in debugging
the actual value it uses, seems ok
otherwise the for x := 0 to 100 wouldn't pass the loop more than once
it's like the watch is wrong

have you tried the logging option ?

what actually is your problem ?
besides the wrong debugger value.

does the app run fine otherwise ?
What you are seeing is correct, and is caused by the code compiler optimizations for loop induction. You have asked for a loop to be executed 101 times, and that is what you will get.
eg:

for i:=0 to 100 do
begin
  beep;
end;

This equates to the following assembly code:

@@example:
MOV EBX, $00000065 // Load EBX with 101
CALL Beep                  // Loop body
DEC EBX                     // Decrement the register
JNZ @@example         // Jump if not zero

You will also find that if you utlilize the loop variable *within* the loop, then the produced code changes, and you will see the "expected" loop var value in the debugger, eg:

for i:=0 to 100 do
begin
  if (i = 20) then beep;
end;

The difference between the 2 is that in the first example you had no requirement to actually evaluate the loop inductor, thus allowing the compiler to generate more effecient code. The second example forces a CMP (compare) instruction to test for 100, which takes 2 clock cycles, vs the 1 for the JNZ.

Hope this helps,
Russell
Russel,
if i understand this correctly :

if you have a loop and you are using this loop variable inside the loop with a comparison
then the debugger will show the value of loop variable in the inverse direction of the loop ?
or is this just for the positive loops (low to high)

so if i want to write faster apps, i should allways write loops from high to low ?

@rllibby

I know the values are correct, this is only a debugging problem and I wanted an explanation for it.

If this is done by the code optimizer why does it still happen if I turn off optimization using {$O-} ?

also you say the asm code will change if I utilize the loop variable. but I do this already if you look at the code.

The line is

BColor[i] := myColor; // i beeing the loop counter, BColor[] an array
ASKER CERTIFIED SOLUTION
Avatar of Russell Libby
Russell Libby
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
you really deserve the genius status for this clear explanation !
Btw,
Delphi 7 has the same issues
@Geert,
Thanks. Hopefully I was a little more clear the second time around. Its good information to have, but in practical use there isn't much application for it; short of interpreter/compiler design.

Russell
I have one remaining question.

My code must perform a

BColor[0] := myColor

and

BColor[100] := myColor

if the compiler choses a loop from 101 to 1 instead, does this mean that the code is changed to something like this?

BColor[i-1] := myColor
i don't think you need to change your code
if you would need to consider the optimisation and take the changes into account not much would work

the loop variable is only wrong in the watch

to check what assembly code the compiler created,
you could set a breakpoint at the beginning of your code
and then open the CPU window

then you may see how BColor[i] will be interpreted

I agree with the above comment...

The compiler is going to produce the correct code, so your only issue is during debugging. Either turn off optimizations and rebuild / test. Or induce the loop variable with a simple if (i = {N}) do something, eg;

   if (i = 10) then OutputDebugString('i is 10');

If you really want to see what the resulting code is doing, then pop the CPU window and trace it that way. It will require that you understand assembly instructions though.

Russell


I did not aks If I need to change the code.

I've asked:

"does this mean that the code IS CHANGED to something like this?

BColor[i-1] := myColor"

I mean if the optimizers changes the code to this. Overwise the code can not work.

So apparently the optimization does not only reserve the loop, it changes the method the array is filled too.
If you perform the following:

>>
BColor[0] := myColor

and

BColor[100] := myColor
<<

then the indexer has no bearing on those 2 statements. If you have further questions then I suggest you open the CPU window to determine what the compiler is executing.