¿Las variables delphi se inicializan con un valor de forma predeterminada?

103

Soy nuevo en Delphi y he estado ejecutando algunas pruebas para ver qué variables de objeto y variables de pila se inicializan de forma predeterminada:

TInstanceVariables = class
  fBoolean: boolean; // always starts off as false
  fInteger: integer; // always starts off as zero
  fObject: TObject; // always starts off as nil
end;

Este es el comportamiento al que estoy acostumbrado en otros idiomas, pero me pregunto si es seguro confiar en él en Delphi. Por ejemplo, me pregunto si podría depender de la configuración de un compilador o quizás funcionar de manera diferente en diferentes máquinas. ¿Es normal confiar en los valores inicializados predeterminados para los objetos o establece explícitamente todas las variables de instancia en el constructor?

En cuanto a las variables de pila (nivel de procedimiento), mis pruebas muestran que los valores booleanos unitarios son verdaderos, los enteros unitarios son 2129993264 y los objetos no inicializados son solo punteros no válidos (es decir, no nulos). Supongo que la norma es establecer siempre variables a nivel de procedimiento antes de acceder a ellas.

MEGABYTE.
fuente
3
Dos notas: 1. Los registros no se inicializan. 2. Las variables contadas de referencia siempre se inicializan. !¡PERO! en una función que devuelve una cadena, 'Resultado' no se inicializa a una cadena vacía como es de esperar. Esto se debe a que 'Result' no es una var local. Entonces, siempre haz: Resultado: = '';
InTheNameOfScience
ver también: ¿Qué variables se inicializan en Delphi?
InTheNameOfScience
¿Responde esto a tu pregunta? ¿Qué variables se inicializan en Delphi?
InTheNameOfScience

Respuestas:

105

Sí, este es el comportamiento documentado:

  • Los campos de objeto siempre se inicializan en 0, 0.0, '', False, nil o lo que corresponda.

  • Las variables globales siempre se inicializan en 0, etc. también;

  • Las variables locales contadas por referencias * siempre se inicializan en cero o '';

  • Las variables locales que no cuentan con referencias * no están inicializadas, por lo que debe asignar un valor antes de poder usarlas.

Recuerdo que Barry Kelly en algún lugar escribió una definición de "referencia contada", pero ya no puedo encontrarla, así que esto debería funcionar mientras tanto:

referencia-contada == que se cuentan por referencia ellos mismos, o que contienen directa o indirectamente campos (para registros) o elementos (para matrices) que se cuentan por referencia como: string, variant, interface o matriz dinámica o matriz estática que contiene tales tipos.

Notas:

  • record en sí mismo no es suficiente para convertirse en referencia contada
  • Todavía no he probado esto con genéricos
Giacomo Degli Esposti
fuente
2
Como señaló Giacomo en los comentarios a continuación, todo esto se explica en los archivos de ayuda de Delphi en ms-help: //borland.bds4/bds4ref/html/Variables.htm. En Delphi 2009 encontré la misma información buscando en la ayuda "variables" (curiosamente probé muchas búsquedas pero no pensé en probar esa).
MB.
8
Las variables locales se inicializan ($ 0) si son de un tipo administrado como cadenas, interfaces, matrices dinámicas o variantes
Francesca
5
¡Sin embargo, hay una excepción! Cuando anula el constructor y no llama al constructor heredado, existe la posibilidad de que algunos campos terminen sin inicializar. (Especialmente con versiones antiguas de Delphi). Dado que TObject.Create es responsable de poner a cero todos los datos, no llamar a ese da como resultado posibles datos desconocidos.
Wim ten Brink
18
@WimtenBrink Creo que estás equivocado. La inicialización no se realiza dentro TObject.Create, que es un método vacío, pero en el class function TObject.InitInstance(Instance: Pointer): TObject;que SIEMPRE se llama antes de cualquier llamada al constructor, incluso para versiones anteriores de Delphi. En mi humilde opinión, su comentario es incorrecto y confuso.
Arnaud Bouchez
7
No olvide que en una función que devuelve una cadena, 'Resultado' no se inicializa a una cadena vacía como podría esperar. Esto se debe a que 'Result' no es una var local.
InTheNameOfScience
27

Las variables globales que no tienen un inicializador explícito se asignan en la sección BSS del ejecutable. En realidad, no ocupan espacio en el EXE; la sección BSS es una sección especial que el sistema operativo asigna y borra a cero. En otros sistemas operativos, existen mecanismos similares.

Puede depender de que las variables globales se inicialicen a cero.

Barry Kelly
fuente
21

Los campos de clase son cero por defecto. Esto está documentado para que pueda confiar en él. Las variables de pila local no están definidas a menos que la cadena o la interfaz se establezcan en cero.

Martín Liesén
fuente
Gracias. "Cero" me confunde un poco, ¿eso significa que las cadenas son "" y las interfaces son nulas?
MB.
4
Sí, exactamente eso. nil = 0 (a nivel de ensamblador) y '' = nil (convención de Delphi).
gabr
1
"a menos que una cadena o una interfaz" no sea una descripción completa de la realidad. Las matrices dinámicas, por ejemplo, también se inicializan. De manera más general, la regla es que las variables de tipos administrados (contados por referencias) se inicializan, incluso si son locales.
Andreas Rejbrand
16

Solo como nota al margen (ya que es nuevo en Delphi): las variables globales se pueden inicializar directamente al declararlas:

var myGlobal:integer=99;
Heinrich Ulbricht
fuente
2
Desde 10.3, lo mismo se aplica a las variables locales
Edijs Kolesnikovičs
1
Y si no se hace explícitamente, se inicializan en 0, 0.0, False, nil, [], etc.
Andreas Rejbrand
7

Aquí hay una cita de Ray Lischner Delphi in a Nutshell Capítulo 2

"Cuando Delphi crea un objeto por primera vez, todos los campos comienzan vacíos, es decir, los punteros se inicializan a cero, las cadenas y las matrices dinámicas están vacías, los números tienen el valor cero, los campos booleanos son falsos y las variantes se configuran como no asignadas. (Consulte NewInstance e InitInstance en el Capítulo 5 para obtener más detalles) ".

Es cierto que las variables locales en el alcance deben inicializarse ... Trataría el comentario anterior de que "Las variables globales se inicializan" como dudoso hasta que se proporcione una referencia; no lo creo.

editar ... Barry Kelly dice que puede depender de que se inicialicen a cero, y dado que él está en el equipo del compilador de Delphi, creo que se mantiene :) Gracias Barry.

Drew Gibson
fuente
1
En la ayuda de delphi 2006, puede encontrarla aquí: ms-help: //borland.bds4/bds4ref/html/Variables.htm "Si no inicializa explícitamente una variable global, el compilador la inicializa a 0. Datos de instancia de objeto ( campos) también se inicializan a 0. "
Giacomo Degli Esposti
Votado en contra debido a "No creo eso". Esto es programación, no religión. Y Giacomo acaba de demostrar la verdad.
InTheNameOfScience
6

Las variables globales y los datos de instancia de objeto (campos) siempre se inicializan a cero. Las variables locales en procedimientos y métodos no se inicializan en Win32 Delphi; su contenido no está definido hasta que les asigne un valor en el código.

Ondrej Kelle
fuente
5

Incluso si un idioma ofrece inicializaciones predeterminadas, no creo que deba confiar en ellas. Inicializar a un valor hace que sea mucho más claro para otros desarrolladores que podrían no conocer las inicializaciones predeterminadas en el lenguaje y evita problemas entre los compiladores.

Thomas Owens
fuente
4
Por supuesto que puede. Y deberías. Inicializar todo a 0 / '' / false / nil en cada constructor es simplemente innecesario. Inicializar variables globales, por otro lado, no es tan estúpido; por una vez, nunca puedo recordar si están inicializadas o no (ya que no las estoy usando mucho).
gabr
2
Si Delphi le permite inicializar una variable en el mismo punto en que la declara (por ejemplo, var fObject: TObject = nil), me inclinaría a estar de acuerdo en que inicializar a un valor es probablemente una buena idea. Pero a mí me parece un poco difícil hacerlo en el constructor para cada campo de objeto.
MB.
4

Desde el archivo de ayuda de Delphi 2007:

ms-help: //borland.bds5/devcommon/variables_xml.html

"Si no inicializa explícitamente una variable global, el compilador la inicializa a 0".

Ondrej Kelle
fuente
3

Tengo una pequeña queja con las respuestas dadas. Delphi pone a cero el espacio de memoria de los globales y los objetos recién creados. Si bien esto NORMALMENTE significa que están inicializados, hay un caso en el que no lo son: tipos enumerados con valores específicos. ¿Y si cero no es un valor legal?

Loren Pechtel
fuente
1
Cero es siempre un valor legal, es el primer valor de la enumeración. puede verlo con ord (MyFirstEnumValue).
Francesca
Devolvería el primer valor del tipo enumerado.
skamradt
6
Cero no siempre es un valor legal si asigna explícitamente valores a la enumeración. En ese caso, todavía se inicializa a 0 y tiene un valor ilegal. Pero las enumeraciones son simplemente azúcar sintáctico pintado sobre tipos enteros normales, por lo que esto realmente no rompe nada. Asegúrese de que su código pueda manejarlo.
Mason Wheeler
2
@ François: No si define su enumeración así:TOneTwoThree = (One=1, Two=2, Three=3);
fnkr
0

Las variables en línea recién introducidas (desde Delphi 10.3) están facilitando el control de los valores iniciales.

procedure TestInlineVariable;
begin
  var index: Integer := 345;
  ShowMessage(index.ToString);
end;
Jacek Krawczyk
fuente