una - ¿Qué variables se inicializan cuando está en Delphi?
tipos de datos y operadores en delphi (4)
Siempre obtengo 0 de enteros y falso de booleanos para todos los miembros de registro.
Intenté activar y desactivar varias opciones de compilación (depuración, optimizaciones, etc.), pero no hubo diferencia. Todos mis miembros de registro están siendo inicializados.
¿Qué me estoy perdiendo?
Bueno, aparte de su prueba, usa variables globales en lugar de locales: lo importante que se está perdiendo es la distinción entre las variables que coincidentemente parecen haberse inicializado, y las variables que se inicializan de manera actal .
Por cierto : esta es la razón por la cual los programadores que no revisan sus advertencias cometen el error común de asumir que su código mal escrito se está comportando correctamente cuando hacen pocas pruebas; sucede que tiene 0 y valores predeterminados falsos .... Want To Buy: random initialisation of local variables for debug builds.
Considere la siguiente variación en su código de prueba:
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.
Con el siguiente resultado de muestra:
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
Notas
- El ejemplo funciona mejor si compila con la optimización desactivada. De lo contrario, si tiene la optimización activada:
- Algunos vars locales serán manipulados en registros de CPU.
- Y si ves la pila de la CPU al pasar por el código, notarás, por ejemplo, que
I := I + 1
ni siquiera modifica la pila. Entonces, obviamente, el cambio no puede llevarse a cabo.
- Puede experimentar con diferentes convenciones de llamadas para ver cómo eso afecta las cosas.
- También puede probar el efecto de establecer los valores locales en cero en lugar de incrementarlos.
- Esto ilustra cómo dependes totalmente de lo que encontró en la pila antes de que se llamara a tu método.
Así que siempre escuché que los campos de clase (basados en el montón) se inicializaban, pero las variables basadas en la pila no. También escuché que los miembros del registro (que también están basados en la pila) tampoco se inicializaron. El compilador advierte que las variables locales no se inicializan ([Advertencia de DCC] W1036 La variable ''x'' podría no haberse inicializado), pero no advierte para miembros de registro. Entonces decidí hacer una prueba.
Siempre obtengo 0 de enteros y falso de booleanos para todos los miembros de registro.
Intenté activar y desactivar varias opciones de compilación (depuración, optimizaciones, etc.), pero no hubo diferencia. Todos mis miembros de registro están siendo inicializados.
¿Qué me estoy perdiendo? Estoy en la Actualización 2 de Delphi 2009.
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.
Salida:
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 Done . . . .
Las variables globales tienen cero inicialización. Las variables utilizadas en el contexto del bloque end
principal ... de un programa pueden ser un caso especial; a veces se tratan como variables locales, particularmente for
indexadores de bucle. Sin embargo, en su ejemplo, r
es una variable global y se asigna desde la sección .bss del archivo ejecutable, que el cargador de Windows garantiza que no se completa.
Las variables locales se inicializan como si se pasaran a la rutina Initialize
. La rutina Initialize
utiliza runtime type-info (RTTI) para poner a cero campos (recursivamente, si un campo es de una matriz o tipo de registro) y arrays (recursivamente, si el tipo de elemento es una matriz o un registro) de un tipo gestionado , donde un tipo administrado es uno de:
- AnsiString
- UnicodeString
- WideString
- un tipo de interfaz (incluyendo referencias de métodos)
- tipo de matriz dinámica
- Variante
Las asignaciones del montón no se inicializan necesariamente; depende de qué mecanismo se utilizó para asignar memoria. Las asignaciones como parte de los datos de objeto de instancia se llenan con cero mediante TObject.InitInstance
. Las asignaciones de AllocMem
están AllocMem
cero, mientras que GetMem
asignaciones de GetMem
no se llenan a cero. Las asignaciones de New
se inicializan como si se pasaran a Initialize
.
Tenga en cuenta que en el código de ejemplo que proporcionó, el registro es en realidad una variable global, por lo que se inicializará por completo. Si mueve todo ese código a una función, será una variable local, y así, según las reglas dadas por Barry Kelly, solo se inicializará su campo de cadena (a '''').
Tengo una situación similar, y pensé lo mismo, pero cuando agrego otras variables utilizadas antes del registro, los valores se vuelven basura, así que antes de usar mi registro tuve que inicializar usando
FillChar(MyRecord, SizeOf(MyRecord), #0)