What variables are initialized in Delphi?

So, I always heard that class fields (heap based) were initialized, but stack based variables were not. I also heard that recording elements (also based on stacks) were also not initialized. The compiler warns that local variables are not initialized ([DCC Warning] W1036 The variable "x" may not have been initialized), but does not warn about the members of a record. Therefore, I decided to conduct a test.

I always get 0 from integers and false from Booleans for all members of the record.

I tried turning on and off various compiler options (debugging, optimization, etc.), but there was no difference. All my members are initialized.

What am I missing? I'm on Delphi 2009 Update 2.

program TestInitialization; {$APPTYPE CONSOLE} uses SysUtils; type TR = Record Public i1, i2, i3, i4, i5: Integer; a: array[0..10] of Integer; b1, b2, b3, b4, b5: Boolean; s: String; End; var r: TR; x: Integer; begin try WriteLn('Testing record. . . .'); WriteLn('i1 ',R.i1); WriteLn('i2 ',R.i2); WriteLn('i3 ',R.i3); WriteLn('i4 ',R.i4); WriteLn('i5 ',R.i5); Writeln( ',Rs); Writeln('Booleans: ', R.b1, ' ', R.b2, ' ', R.b3, ' ', R.b4, ' ', R.b5); Writeln('Array '); for x := 0 to 10 do Write(Ra[x], ' '); WriteLn; WriteLn('Done . . . .'); except on E:Exception do Writeln(E.Classname, ': ', E.Message); end; ReadLn; end. 

Output:

 Testing record.  .  .  .
 i1 0
 i2 0
 i3 0
 i4 0
 i5 0
 S
 Booleans: FALSE FALSE FALSE FALSE FALSE
 Array
 0 0 0 0 0 0 0 0 0 0 0 0
 Done  .  .  .

+29
variables initialization delphi delphi-2009
May 14 '09 at
source share
4 answers

Global variables are initialized to zero. The variables used in the context of the main block of the begin .. end program can be a special case; they are sometimes treated as local variables, especially for -loop indexers. However, in your example, r is a global variable and stands out from the .bss section of the executable provided by the Windows boot loader.

Local variables are initialized as if they were passed to the Initialize procedure. The Initialize routine uses the runtime-type (RTTI) for null fields (recursively β€” if the field has an array or record type) and arrays (recursively β€” if the element type is an array or record) a managed type, where the managed type is one of:

  • Ansistring
  • Unicodestring
  • Widestring
  • interface type (including method references)
  • dynamic array type
  • Option

Heap allocations are not necessarily initialized; it depends on what mechanism was used to allocate memory. Allocations as part of the data of the instance object are filled with zeros of TObject.InitInstance . AllocMem are padded with zeros, and GetMem allocations are not padded with zeros. Allocations from New initialized as if they were passed to Initialize .

+42
May 14 '09 at 1:32 a.m.
source share

I always get 0 from integers and false from Booleans for all elements of the record.

I tried turning on and off various compiler options (debugging, optimization, etc.), but there was no difference. All my members are initialized.

What am I missing?

Well, in addition to your test, using global instead of local variables: it is important that you are absent - this is the difference between variables that randomly appear to initialize and variables that act . BTW . That is why programmers who do not check their warnings make a common mistake, assuming that their poorly written code behaves correctly when several tests are performed; have 0 and False default values ​​.... Want To Buy: random initialisation of local variables for debug builds.

Consider the following test code:

 program LocalVarInit; {$APPTYPE CONSOLE} procedure DoTest; var I, J, K, L, M, N: Integer; S: string; begin Writeln('Test default values'); Writeln('Numbers: ', I:10, J:10, K:10, L:10, M:10, N:10); Writeln('S: ', S); I := I + 1; J := J + 2; K := K + 3; L := L + 5; M := M + 8; N := N + 13; S := 'Hello'; Writeln('Test modified values'); Writeln('Numbers: ', I:10, J:10, K:10, L:10, M:10, N:10); Writeln('S: ', S); Writeln(''); Writeln(''); end; begin DoTest; DoTest; Readln; end. 

With the following output:

 Test default values Numbers: 4212344 1638280 4239640 4239632 0 0 S: Test modified values Numbers: 4212345 1638282 4239643 4239637 8 13 //Local vars on stack at end of first call to DoTest S: Hello Test default values Numbers: 4212345 1638282 4239643 4239637 8 13 //And the values are still there on the next call S: Test modified values Numbers: 4212346 1638284 4239646 4239642 16 26 S: Hello 

Notes

  • The example is best suited for compilation with optimization. Otherwise, if you have optimization:
    • Some local vars will be processed in the CPU register.
    • And if you look at the processor stack, going through the code, you will notice, for example, that I := I + 1 does not even modify the stack. Therefore, it is obvious that the change cannot be made.
  • You can experiment with various calling conventions to see how this affects things.
  • You can also check the effect of setting local bars to zero, rather than increasing them.
  • This illustrates how you are completely dependent on finding your way onto the stack before your method was called.
+6
Apr 24 '11 at 19:01
source share

I have the same situation and I thought the same thing, but when I add other variables used before the record, the values ​​become garbage, so before I used my record, I had to initialize with

 FillChar(MyRecord, SizeOf(MyRecord), #0) 
+1
May 14 '09 at 1:31 a.m.
source share

Note that in the code example you provided, the record is actually a global variable, so it will be fully initialized. If you move all this code into a function, it will be a local variable, and therefore, in accordance with the rules given by Barry Kelly, only its string field (before '') will be initialized.

+1
May 14 '09 at 9:56 a.m.
source share



All Articles