Les variables delphi sont-elles initialisées avec une valeur par défaut?

103

Je suis nouveau dans Delphi et j'ai exécuté des tests pour voir sur quelles variables objet et variables de pile sont initialisées par défaut:

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

C'est le comportement auquel je suis habitué dans d'autres langages, mais je me demande s'il est sûr de s'appuyer dessus dans Delphi? Par exemple, je me demande si cela pourrait dépendre d'un paramètre du compilateur, ou peut-être fonctionner différemment sur différentes machines. Est-il normal de s'appuyer sur les valeurs initialisées par défaut pour les objets ou définissez-vous explicitement toutes les variables d'instance dans le constructeur?

En ce qui concerne les variables de pile (au niveau de la procédure), mes tests montrent que les booléens unitialisés sont vrais, les entiers unitialisés sont 2129993264 et les objets non initialisés ne sont que des pointeurs invalides (c'est-à-dire non nuls). Je suppose que la norme est de toujours définir des variables au niveau de la procédure avant d'y accéder?

MB.
la source
3
Deux remarques: 1. Les enregistrements ne sont pas initialisés. 2. Les variables comptées de référence sont toujours initialisées. !MAIS! dans une fonction qui renvoie une chaîne, 'Result' n'est pas initialisé à une chaîne vide comme vous pouvez vous y attendre. C'est parce que 'Result' n'est pas une variable locale. Alors, faites toujours: Result: = '';
InTheNameOfScience
Est-ce que cela répond à votre question? Quelles variables sont initialisées dans Delphi?
InTheNameOfScience

Réponses:

105

Oui, c'est le comportement documenté:

  • Les champs d'objets sont toujours initialisés à 0, 0.0, '', False, nil ou ce qui s'applique.

  • Les variables globales sont toujours initialisées à 0, etc.

  • Les variables locales comptées par référence * sont toujours initialisées à nil ou '';

  • Les variables locales sans référence * ne sont pas initialisées, vous devez donc attribuer une valeur avant de pouvoir les utiliser.

Je me souviens que Barry Kelly a écrit quelque part une définition de "référence-comptée", mais ne peut plus la trouver, donc cela devrait faire entre-temps:

référence compté == qui sont eux - mêmes le comptage de références, ou contenir directement ou indirectement champs (pour les documents) ou des éléments (pour les tableaux) qui sont comptées comme référence: string, variant, interface ou tableau dynamique ou tableau statique contenant ces types.

Remarques:

  • record lui-même ne suffit pas pour devenir une référence
  • Je n'ai pas encore essayé cela avec des génériques
Giacomo Degli Esposti
la source
2
Comme Giacomo l'a souligné dans les commentaires ci-dessous, tout cela est expliqué dans les fichiers d'aide Delphi à ms-help: //borland.bds4/bds4ref/html/Variables.htm. Dans Delphi 2009, j'ai trouvé la même information en cherchant dans l'aide "variables" (assez curieusement, j'ai essayé beaucoup de recherches mais je n'ai pas pensé essayer celle-là).
MB.
8
Les variables locales SONT initialisées ($ 0) si elles sont d'un type géré comme des chaînes, des interfaces, des tableaux dynamiques ou des variantes
Francesca
5
Il y a cependant une exception! Lorsque vous remplacez le constructeur et n'appelez pas le constructeur hérité, il est possible que certains champs ne soient pas initialisés! (Surtout avec les anciennes versions de Delphi.) Étant donné que TObject.Create est responsable de la remise à zéro de toutes les données, ne pas appeler cela entraîne de possibles données inconnues.
Wim ten Brink
18
@WimtenBrink Je pense que vous vous trompez. L'initialisation ne se fait pas à l'intérieur TObject.Create, qui est une méthode void, mais dans class function TObject.InitInstance(Instance: Pointer): TObject;laquelle est TOUJOURS appelée avant tout appel de constructeur, même pour les anciennes versions de Delphi. Votre commentaire est à mon humble avis faux et déroutant.
Arnaud Bouchez
7
N'oubliez pas que dans une fonction qui renvoie une chaîne, 'Result' n'est pas initialisé à une chaîne vide comme vous pouvez vous y attendre. C'est parce que 'Result' n'est pas une variable locale.
InTheNameOfScience
27

Les variables globales qui n'ont pas d'initialiseur explicite sont allouées dans la section BSS de l'exécutable. Ils ne prennent en fait aucun espace dans l'EXE; la section BSS est une section spéciale que le système d'exploitation alloue et efface à zéro. Sur d'autres systèmes d'exploitation, il existe des mécanismes similaires.

Vous pouvez compter sur des variables globales initialisées à zéro.

Barry Kelly
la source
21

Les champs de classe sont zéro par défaut. Ceci est documenté afin que vous puissiez vous y fier. Les variables de la pile locale ne sont pas définies, sauf si la chaîne ou l'interface sont définies sur zéro.

Martin Liesén
la source
Merci. "Zéro" me déroute un peu - cela signifie-t-il que les chaînes sont '' et que les interfaces sont nulles?
MB.
4
Oui, exactement ça. nil = 0 (au niveau assembleur) et '' = nil (convention Delphi).
gabr
1
"à moins qu'une chaîne ou une interface" n'est pas une description complète de la réalité. Les tableaux dynamiques, par exemple, sont également initialisés. Plus généralement, la règle est que les variables de types gérés (comptés par référence) sont initialisées, même si elles sont locales.
Andreas Rejbrand
16

Juste comme note d'accompagnement (comme vous êtes nouveau dans Delphi): les variables globales peuvent être initialisées directement lors de leur déclaration:

var myGlobal:integer=99;
Heinrich Ulbricht
la source
2
Depuis 10.3, il en va de même pour les variables locales
Edijs Kolesnikovičs
1
Et si ce n'est pas fait explicitement, ils sont initialisés à 0, 0.0, False, nil, [], etc.
Andreas Rejbrand
7

Voici une citation de Ray Lischners Delphi en bref Chapitre 2

«Lorsque Delphi crée un objet pour la première fois, tous les champs commencent vides, c'est-à-dire que les pointeurs sont initialisés à nil, les chaînes et les tableaux dynamiques sont vides, les nombres ont la valeur zéro, les champs booléens sont False et les Variants sont définis sur Unassigned. (Voir NewInstance et InitInstance au chapitre 5 pour plus de détails.) "

Il est vrai que les variables locales dans la portée doivent être initialisées ... Je traiterais le commentaire ci-dessus selon lequel "les variables globales sont initialisées" comme douteux jusqu'à ce qu'ils soient fournis avec une référence - je ne le crois pas.

edit ... Barry Kelly dit que vous pouvez compter sur leur initialisation à zéro, et comme il fait partie de l'équipe de compilation Delphi, je crois que cela vaut :) Merci Barry.

Drew Gibson
la source
1
Dans l'aide delphi 2006, vous pouvez le trouver ici: ms-help: //borland.bds4/bds4ref/html/Variables.htm "Si vous n'initialisez pas explicitement une variable globale, le compilateur l'initialise à 0. Données d'instance d'objet ( champs) sont également initialisés à 0. "
Giacomo Degli Esposti
Évalué à cause de "Je ne crois pas cela". C'est de la programmation, pas de la religion. Et Giacomo vient de démontrer la vérité.
InTheNameOfScience
6

Les variables globales et les données (champs) d'instance d'objet sont toujours initialisées à zéro. Les variables locales dans les procédures et méthodes ne sont pas initialisées dans Win32 Delphi; leur contenu n'est pas défini tant que vous ne leur attribuez pas une valeur dans le code.

Ondrej Kelle
la source
5

Même si un langage propose des initialisations par défaut, je ne pense pas que vous devriez vous y fier. L'initialisation à une valeur le rend beaucoup plus clair pour les autres développeurs qui pourraient ne pas connaître les initialisations par défaut dans le langage et évite les problèmes entre les compilateurs.

Thomas Owens
la source
4
Bien sûr vous pouvez. Et tu devrais. Tout initialiser à 0 / '' / false / nil dans chaque constructeur est simplement inutile. L'initialisation des variables globales, par contre, n'est pas si stupide - pour une fois, je ne me souviens jamais si elles sont initialisées ou non (car je ne les utilise pas beaucoup).
gabr le
2
Si Delphi vous laisse initialiser une variable au même point que vous la déclarez (par exemple var fObject: TObject = nil), je serais enclin à admettre que l'initialisation à une valeur est probablement une bonne idée. Mais pour moi, il semble un peu difficile de le faire dans le constructeur pour chaque champ objet.
MB.
4

Depuis le fichier d'aide de Delphi 2007:

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

"Si vous n'initialisez pas explicitement une variable globale, le compilateur l'initialise à 0."

Ondrej Kelle
la source
3

J'ai un petit reproche avec les réponses données. Delphi met à zéro l'espace mémoire des globaux et des objets nouvellement créés. Bien que cela signifie NORMALEMENT qu'ils sont initialisés, il existe un cas où ils ne le sont pas: les types énumérés avec des valeurs spécifiques. Et si zéro n'est pas une valeur légale ??

Loren Pechtel
la source
1
Zéro est toujours une valeur légale, c'est la 1ère valeur de l'énumération. vous pouvez le voir avec ord (MyFirstEnumValue).
Francesca
Il renverrait la première valeur du type énuméré.
skamradt
6
Zéro n'est pas toujours une valeur légale si vous affectez explicitement des valeurs à l'énumération. Dans ce cas, il est toujours initialisé à 0 et vous avez une valeur non conforme. Mais les énumérations ne sont que du sucre syntaxique peint sur des types entiers normaux, donc cela ne brise vraiment rien. Assurez-vous que votre code peut le gérer.
Mason Wheeler
2
@ François: Pas si vous définissez votre énumération comme ceci:TOneTwoThree = (One=1, Two=2, Three=3);
fnkr
0

Les variables inline nouvellement introduites (depuis Delphi 10.3) facilitent le contrôle des valeurs initiales.

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