6

I believe that local integer variables are not initialized to zero in delphi. The initial value is whatever happens to be at that memory location. So in the code below the first time the button is clicked the first message shows a integer value. How come the second time it's clicked it doesn't show 3 but instead shows the same integer value? It continues to show the same integer value each time I click the button. The value is different only when I stop and restart the program. Where is 3 being stored as it looks like the same memory location is used each time the button is clicked in the same run of the program?

procedure TForm1.Button1Click(Sender: TObject);

var
int1 : integer;

begin
   showmessage(inttostr(int1)) ;
   int1 := 3;
end;

end.
kjack
  • 2,004
  • 3
  • 26
  • 41
  • See this comment: http://stackoverflow.com/questions/132725/are-delphi-variables-initialized-with-a-value-by-default – pritaeas Feb 12 '09 at 12:05

6 Answers6

12

kjack,

It contains whatever value is in the stack frame at that time. In your case, this will be Sender. If you'd take the integer and typecast it to an object you'll notice the "pattern".

procedure TForm1.Button1Click(Sender: TObject);

var
int1 : integer;

begin
   ShowMessage(TObject(int1).ClassName);
   showmessage(inttostr(int1)) ;
   int1 := 3;
end;

end.
Lieven Keersmaekers
  • 57,207
  • 13
  • 112
  • 146
  • Not exactly, int1 and Sender are not defined on the same space. (Although this is possible using the absolute directive). – Toon Krijthe Feb 12 '09 at 12:34
  • yes ShowMessage(TObject(int1).ClassName); keeps showing TButton so I think you're right. I'm a bit lost at the moment though – kjack Feb 12 '09 at 12:35
  • @Gamecat, can you elaborate? Sender is always passed in eax. int1 get's its initial value from [ebp-4]. As for "this" code, it always resolves to Sender. Am I missing something? – Lieven Keersmaekers Feb 12 '09 at 13:13
  • It may not always resolve to Sender, given enough changes to VCL code. – mghie Feb 12 '09 at 13:16
  • @mghie. Perhaps true but I doubt codegear will change the ButtonClick eventhandler's parameter list in the near future. – Lieven Keersmaekers Feb 12 '09 at 14:19
  • 1
    No, Lieven, Sender is not passed in EAX. It's passed in EDX. Self is passed in EAX. Int1 might come from the stack, or it might come from a register; that's the compilers decision. And the act of calling the ClassName function may change the generated code to something else. – Rob Kennedy Feb 12 '09 at 14:57
  • @Rob, EDX, you're right offcourse, my mistake. For the op's original question with that particular piece of code and always using the same compiler at the exact same hour of the exact same day (you'll get the picture :), I'm pretty sure int1 will always get initialized to [ebp-4] being Self. – Lieven Keersmaekers Feb 12 '09 at 15:21
  • Cool. I learn something new every day. Probably best not to use it in my code though! :) – Toby Allen Feb 13 '09 at 12:51
5

Firstly, you're correct that local variables aren't initialised.

Also you can't guarantee that int1 is being stored in the same memory location on each invocation. In this case it could be that the reason you're seeing the same value each time is because it is using the same location (by chance) but the Delphi compiler has optimised away your final

int1 := 3;

statement as it has no effect. (You can add another showmessage(inttostr(int1)) call after that line and see if that makes a difference.) Another possibility is that the memory location used for int1 is reused between calls to your button handler (say in the Windows message loop) and that happens to always reset it to the value you're seeing.

Community
  • 1
  • 1
Mark Pim
  • 9,898
  • 7
  • 40
  • 59
2

This will only be true if you execute no other code between two clicks on Button1, most importantly code that uses the same amount of (or more) stack space than the code to arrive at procedure TForm1.Button1Click() uses. Unless you overwrite values on the stack they will still contain the same value.

What you could do to test this is to add another button with an OnClick handler that calls a method with more parameters than ShowMessage() has. If you click that button between two clicks on Button1, the value of int1 should indeed change. That is because the stack location for int1 in Button1Click() will then be used for one of the parameters in your other handler, and get overwritten.

The assignment should be optimized away, you can see this as the line should not have the blue dot in the gutter area. There should be a compiler hint as well.

Edit: As you commented there seems to be no change in behaviour when another button is clicked. From that I can only assume that the VCL code (which is executed before the OnClick handler is called) uses so much stack space that the memory location for int1 is always initialized with some (stable) value. This code does always the same, so if the addresses of the involved objects (Application, parent form and button) do not change the value will also stay the same. OTOH restarting the application will yield a new, equally stable value in the uninitialized local variable.

Note that this is all highly dependent on the VCL code executed before the handler, so changes to the VCL might change it too. It may even be that various Delphi versions already behave differently.

mghie
  • 32,028
  • 6
  • 87
  • 129
  • I put in a second button as you suggested but it did not alter the behaviour on clicking button1. Lieven answer seems to be the correct one. – kjack Feb 12 '09 at 13:07
1

Local variables are in the stack frame. And they are not initialized.

If you access a method twice, you have a chance the stackpointer is euqal which gives the same values.

Example:

Stack before call:

> More stack  (memory location X)

If Button1Click is called, the stack is like:

> Int1
> Return address
> Sender
> Self pointer
> More stack  (memory location X)

If the next time, Button1Click is called, the stackpointer is still on location X, and no other function has changed the values, you will find the same value for Int1.

If you have secure information, it is always wise to clear the local variables (but you have a chance that the optimizer removes these states. So you neet to disable optimizing).

Just for fun, add another button:

procedure TForm1.Button2Click(Sender: TObject);
var
  int1 : integer;
begin
  showmessage(inttostr(int1)) ;
  int1 := 777;
end;

And check:

  • click 1: garbage
  • click 1 again: 3
  • click 2: 3
  • click 1: 777
Toon Krijthe
  • 52,876
  • 38
  • 145
  • 202
  • I did this and I got garbage for all clicks and it was the same garbage for both buttons every time! Again it only changed once I stopped and restarted the program. I think the garbage figure actually refers to TButton as Lieven says – kjack Feb 12 '09 at 12:39
  • Actually just ran it again and the garbage for the 2 buttons is different but it is still garbage on both – kjack Feb 12 '09 at 12:42
  • @kjack: It is not garbage, it is a leftover pointer to the button that was clicked, originating from the VCL code that ultimately calls your OnClick handler. That's why it is a different value for different buttons being clicked. – mghie Feb 12 '09 at 13:14
  • 1
    Self and Sender aren't on the stack. They're in registers. Int1 is likely in a register as well. The temporary location for the return value from IntToStr will be on the stack, but if Int1 is on the stack, they'll be in different places. – Rob Kennedy Feb 12 '09 at 15:00
1

Do you want it to be the same? If so, you could use a local const:

procedure TForm1.Button1Click(Sender: TObject);
const
  i: integer = 0;
begin
  i := i + 1;
  edit1.text := intToStr(i);
end;

You have to assure 'Assignable typed constants' is switched on though.

Vegar
  • 12,828
  • 16
  • 85
  • 151
  • No...I think you should never ever do this. – J... Jun 16 '13 at 20:04
  • 'No, it doesn't work like this', or 'no, even thou this works, it's not a good idea because...'? – Vegar Jun 18 '13 at 11:11
  • I didn't say it didn't work, I'm simply suggesting that using this in anything other than academic code is to be strongly avoided. It is a design tool whose use demands an extremely compelling argument in its favour to justify tolerating the myriad of obvious complications it introduces over the many other readily available and sane alternatives. – J... Jun 18 '13 at 11:30
  • What 'myriad of obvious complications' does it introduce exactly? Does it leak memory? Does it produce random compiler failure? Hard to find bugs in your software? I have written 'non-academic' delphi code with assignable typed consts for 15 years without experiencing these obvious complications... – Vegar Jun 18 '13 at 17:41
  • I don't intend to have a debate. If you really want a good list of reasons, post a question on the topic. Otherwise, I think there is already sufficient information in this comment thread. – J... Jun 18 '13 at 18:25
0

Initializng variables may or may not be done by the memory manager.

I would consider it good practice of any memory manager to initialize all variables to zero (0x0000). Thats done in .Net as well.

oɔɯǝɹ
  • 7,219
  • 7
  • 58
  • 69