Které proměnné jsou inicializovány, když v Delphi?

hlasů
31

Takže jsem vždycky slyšel, že třída pole (haldy založené) byla inicializována, ale proměnné zásobník na bázi nebyli. Také jsem slyšel, že členové rekord (také je zásobník umístěný) rovněž nebyly inicializovat. Kompilátor varuje, že lokální proměnné nejsou inicializovány ([DCC Warning] W1036 proměnnou ‚x‘, nemusí být inicializován), ale nevaruje pro členy rekordní. Tak jsem se rozhodl spustit test.

Vždycky jsem si 0 z celých čísel a false z Boolean pro všechny členy rekordní.

Snažil jsem se obrátil různé možnosti kompilátoru (ladění, optimalizační, atd.), zapnutí a vypnutí, ale tam byl žádný rozdíl. Všichni mí členové záznam jsou inicializovány.

Co jsem chybí? Jsem na 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('S ',R.s);

    Writeln('Booleans: ', R.b1, ' ', R.b2, ' ', R.b3, ' ', R.b4, ' ', R.b5);

    Writeln('Array ');
    for x := 0 to 10 do
      Write(R.a[x], ' ');
    WriteLn;

    WriteLn('Done . . . .');
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
  ReadLn;
end.

Výstup:

Testování záznam. , , ,
i1 0
i2 0
i3 0
i4 0
i5 0
S
Booleans: FALSE FALSE FALSE FALSE FALSE
řada
0 0 0 0 0 0 0 0 0 0 0
Hotovo . , , ,

Položena 14/05/2009 v 01:21
zdroj uživatelem
V jiných jazycích...                            


4 odpovědí

hlasů
1

Mám podobné situaci, a myslel to samé, ale když jsem se přidat další proměnné používané před záznamem hodnoty stávají odpadky, takže předtím, než jsem se použít svůj rekord musel jsem inicializovat pomocí

FillChar(MyRecord, SizeOf(MyRecord), #0)
Odpovězeno 14/05/2009 v 02:31
zdroj uživatelem

hlasů
44

Globální proměnné jsou nulové inicializovat. Proměnné použité v rámci hlavního begin.. endblok programu může být zvláštní případ; Někdy se s nimi zachází jako lokální proměnné, zejména for-loop indexers. Avšak ve svém příkladu rje globální proměnné a přidělovány z bss části spustitelný, který zavaděč Windows zajišťuje nulový výplní.

Lokální proměnné jsou inicializovány jako kdyby byly předány Initializerutiny. InitializeRutinní použití runtime typ informací (RTTI) na nulu-out oblastech (rekurzivně - pokud je pole z pole nebo záznam typu) a pole (rekurzivně - v případě, že typ element je pole nebo záznam) spravované typu, kde se podařilo typ je jeden z následujících:

  • AnsiString
  • UnicodeString
  • WideString
  • AN (včetně metody referencí) rozhraní
  • dynamický typ pole
  • Varianta

Alokace z haldy nejsou nutně inicializována; záleží na tom, jaký mechanismus byl použit k přidělení paměti. Alokace v rámci stupně jsou objektová data nulové zaplněn TObject.InitInstance. Přidělené prostředky AllocMemjsou nulové naplněné, zatímco GetMemalokace nejsou nulové vyplněna. Alokace ze Newjsou inicializovány jako kdyby byly předány Initialize.

Odpovězeno 14/05/2009 v 02:32
zdroj uživatelem

hlasů
1

Všimněte si, že v příkladu kódu, který za předpokladu, záznam je vlastně globální proměnné, takže to bude úplně inicializována. Pokud přesunete celý tento kód do funkce, bude to lokální proměnná, a tak podle pravidel daných Barry Kelly, pouze jeho řetězec pole bude inicializován (na ‚‘).

Odpovězeno 14/05/2009 v 10:56
zdroj uživatelem

hlasů
6

Vždycky jsem si 0 z celých čísel a false z Boolean pro všechny členy rekordní.

Snažil jsem se obrátil různé možnosti kompilátoru (ladění, optimalizační, atd.), zapnutí a vypnutí, ale tam byl žádný rozdíl. Všichni mí členové záznam jsou inicializovány.

Co jsem chybí?

No, na rozdíl od svého testu za použití globální namísto lokálních proměnných: důležitá věc, že vám něco chybí, je rozdíl mezi proměnnými, které shodou okolností se zdají být inicializace a proměnných, které actally jsou inicializována.
BTW : To je důvod, programátoři, kteří nemají kontrolovat jejich varování, aby společný chybou předpokládat jejich špatně napsaný kód se chová správně, když se několik testů dělají; stalo se, že 0 a False výchozí ....Want To Buy: random initialisation of local variables for debug builds.

Předpokládejme následující variaci na testovacím kódu:

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.

S následující ukázce výstupu:

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

Poznámky

  • Tento příklad nejlépe funguje, pokud kompilace s optimalizací off. V opačném případě, pokud máte optimalizace na:
    • Některé místní vars bude manipulováno v registrech procesoru.
    • A pokud zobrazení zásobníku procesoru, zatímco krokování kódu Všimněte si například, že I := I + 1ani změnit stoh papírů. Je tedy zřejmé, tato změna nemůže být provedena prostřednictvím.
  • Dalo by se experimentovat s různými konvencemi volání vidět, jak to ovlivní věci.
  • Můžete také vyzkoušet vliv nastavení místní Vars na nulu namísto jejich zvyšování.
  • To ukazuje, jak jsou zcela závislé na tom, co si našel cestu do zásobníku předtím, než byla volána vaše metoda.
Odpovězeno 24/04/2011 v 20:01
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more