Le variabili delphi sono inizializzate con un valore per impostazione predefinita?


103

Sono nuovo di Delphi e ho eseguito alcuni test per vedere quali variabili oggetto e variabili di stack sono inizializzate per impostazione predefinita:

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

Questo è il comportamento a cui sono abituato da altre lingue, ma mi chiedo se sia sicuro fare affidamento su di esso in Delphi? Ad esempio, mi chiedo se potrebbe dipendere da un'impostazione del compilatore o forse funzionare in modo diverso su macchine diverse. È normale fare affidamento sui valori inizializzati predefiniti per gli oggetti o si impostano esplicitamente tutte le variabili di istanza nel costruttore?

Per quanto riguarda le variabili stack (a livello di procedura), i miei test mostrano che i booleani unitializzati sono veri, gli interi unitializzati sono 2129993264 e gli oggetti non inizializzati sono solo puntatori non validi (cioè non nulli). Immagino che la norma sia quella di impostare sempre le variabili a livello di procedura prima di accedervi?


3
Due note: 1. I record non vengono inizializzati. 2. Le variabili conteggiate di riferimento vengono sempre inizializzate. !MA! in una funzione che restituisce una stringa, "Risultato" non viene inizializzato in una stringa vuota come ci si potrebbe aspettare. Questo perché "Result" non è una variabile locale. Quindi, fai sempre: Risultato: = '';
InTheNameOfScience


Risposte:


105

Sì, questo è il comportamento documentato:

  • I campi oggetto sono sempre inizializzati su 0, 0,0, '', False, nil o qualsiasi altra cosa si applichi.

  • Anche le variabili globali sono sempre inizializzate su 0 ecc .;

  • Le variabili locali conteggiate in riferimento * sono sempre inizializzate a zero o '';

  • Le variabili locali non conteggiate in riferimento * non sono inizializzate, quindi è necessario assegnare un valore prima di poterle utilizzare.

Ricordo che Barry Kelly da qualche parte ha scritto una definizione per "riferimento conteggiato", ma non riesce più a trovarla, quindi questo dovrebbe fare nel frattempo:

conteggio dei riferimenti == che vengono conteggiati in base ai riferimenti oppure contengono direttamente o indirettamente campi (per i record) o elementi (per gli array) che sono conteggiati in riferimento come: string, variant, interface o array dinamico o array statico contenente tali tipi.

Appunti:

  • record di per sé non è sufficiente per essere contato come riferimento
  • Non l'ho ancora provato con i generici

2
Come ha sottolineato Giacomo nei commenti seguenti, tutto questo è spiegato nei file di aiuto di Delphi su ms-help: //borland.bds4/bds4ref/html/Variables.htm. In Delphi 2009 ho trovato le stesse informazioni cercando nell'help per "variabili" (stranamente ho provato molte ricerche ma non pensavo di provare quella).
MB.

8
Le variabili locali SONO inizializzate ($ 0) se sono di tipo gestito come stringhe, interfacce, array dinamici o varianti
Francesca

5
C'è un'eccezione, però! Quando sovrascrivi il costruttore e non chiami il costruttore ereditato, c'è la possibilità che alcuni campi finiscano per non essere inizializzati! (Specialmente con le versioni precedenti di Delphi.) Poiché TObject.Create è responsabile dell'azzeramento di tutti i dati, non chiamare quello risulta in possibili dati sconosciuti.
Wim ten Brink

18
@WimtenBrink Penso che ti sbagli. L'inizializzazione non viene eseguita all'interno TObject.Create, che è un metodo void, ma in class function TObject.InitInstance(Instance: Pointer): TObject;cui viene SEMPRE chiamato prima di qualsiasi chiamata al costruttore, anche per le versioni precedenti di Delphi. Il tuo commento è IMHO sbagliato e confuso.
Arnaud Bouchez

7
Non dimenticare che in una funzione che restituisce una stringa, "Risultato" non è inizializzato in una stringa vuota come ci si potrebbe aspettare. Questo perché "Result" non è una variabile locale.
InTheNameOfScience

27

Le variabili globali che non hanno un inizializzatore esplicito vengono allocate nella sezione BSS dell'eseguibile. In realtà non occupano spazio nell'EXE; la sezione BSS è una sezione speciale che il sistema operativo assegna e cancella a zero. Su altri sistemi operativi esistono meccanismi simili.

Puoi dipendere dall'inizializzazione delle variabili globali.


21

I campi delle classi sono di default zero. Questo è documentato in modo che tu possa fare affidamento su di esso. Le variabili dello stack locale non sono definite a meno che la stringa o l'interfaccia non siano impostate su zero.


Grazie. "Zero" mi confonde un po ': significa che le stringhe sono "" e le interfacce sono nulle?
MB.

4
Sì, esattamente quello. nil = 0 (a livello di assemblatore) e '' = nil (convenzione Delphi).
gabr

1
"a meno che stringa o interfaccia" non è una descrizione completa della realtà. Anche gli array dinamici, ad esempio, vengono inizializzati. Più in generale, la regola è che le variabili dei tipi gestiti (con conteggio dei riferimenti) vengono inizializzate, anche se locali.
Andreas Rejbrand

16

Proprio come una nota a margine (dato che sei nuovo in Delphi): le variabili globali possono essere inizializzate direttamente quando le dichiari:

var myGlobal:integer=99;

2
Dalla 10.3 lo stesso vale per le variabili locali
Edijs Kolesnikovičs

1
E se non vengono eseguiti in modo esplicito, vengono inizializzati a 0, 0,0, False, nil, [], ecc.
Andreas Rejbrand

7

Ecco una citazione di Ray Lischners Delphi in a Nutshell Capitolo 2

"Quando Delphi crea per la prima volta un oggetto, tutti i campi iniziano vuoti, ovvero i puntatori vengono inizializzati a zero, le stringhe e gli array dinamici sono vuoti, i numeri hanno il valore zero, i campi booleani sono False e le varianti sono impostate su Unassigned. (Vedere NewInstance e InitInstance nel Capitolo 5 per i dettagli.) "

È vero che le variabili local-in-scope devono essere inizializzate ... Tratterei il commento sopra che "le variabili globali sono inizializzate" come dubbio fino a quando non viene fornito un riferimento - non ci credo.

modifica ... Barry Kelly dice che puoi fare affidamento sul fatto che siano inizializzati a zero, e dal momento che fa parte del team di compilatori Delphi credo che sia valido :) Grazie Barry.


1
In delphi 2006 help puoi trovarlo qui: ms-help: //borland.bds4/bds4ref/html/Variables.htm "Se non inizializzi esplicitamente una variabile globale, il compilatore la inizializza a 0. Dati istanza oggetto ( anche i campi) vengono inizializzati a 0. "
Giacomo Degli Esposti

Downvoted a causa di "Non ci credo". Questa è programmazione, non religione. E Giacomo ha appena dimostrato la verità.
InTheNameOfScience

6

Le variabili globali e i dati dell'istanza dell'oggetto (campi) vengono sempre inizializzati a zero. Le variabili locali nelle procedure e nei metodi non vengono inizializzate in Win32 Delphi; il loro contenuto non è definito fino a quando non si assegna loro un valore nel codice.


5

Anche se una lingua offre inizializzazioni predefinite, non credo che dovresti fare affidamento su di esse. L'inizializzazione su un valore rende molto più chiaro agli altri sviluppatori che potrebbero non conoscere le inizializzazioni predefinite nella lingua e previene i problemi tra i compilatori.


4
Certo che puoi. E dovresti. Inizializzare tutto su 0 / '' / false / nil in ogni costruttore non è necessario. Inizializzare le variabili globali, d'altra parte, non è così stupido: per una volta non riesco mai a ricordare se sono inizializzate o meno (dato che non le sto usando molto).
gabr

2
Se Delphi ti permette di inizializzare una variabile nello stesso punto in cui la dichiari (es. Var fObject: TObject = nil) sarei propenso a concordare sul fatto che l'inizializzazione su un valore è probabilmente una buona idea. Ma a me sembra un po 'troppo farlo nel costruttore per ogni campo oggetto.
MB.

4

Dal file della guida di Delphi 2007:

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

"Se non si inizializza esplicitamente una variabile globale, il compilatore la inizializza a 0."


3

Ho una piccola lamentela con le risposte fornite. Delphi azzera lo spazio di memoria delle globali e degli oggetti appena creati. Sebbene questo NORMALMENTE significhi che sono inizializzati, c'è un caso in cui non lo sono: tipi enumerati con valori specifici. E se zero non fosse un valore legale?


1
Zero è sempre un valore legale, è il primo valore dell'enumerazione. puoi vederlo con ord (MyFirstEnumValue).
Francesca

Restituirà il primo valore nel tipo enumerato.
skamradt

6
Zero non è sempre un valore legale se assegni esplicitamente valori all'enumerazione. In tal caso, è ancora inizializzato a 0 e hai un valore illegale. Ma le enumerazioni sono solo zucchero sintattico dipinto su normali tipi interi, quindi questo non rompe davvero nulla. Assicurati che il tuo codice possa gestirlo.
Mason Wheeler

2
@ François: No, se definisci la tua TOneTwoThree = (One=1, Two=2, Three=3);
enumerazione in

0

Le variabili inline di nuova introduzione (da Delphi 10.3) stanno rendendo più facile il controllo dei valori iniziali.

procedure TestInlineVariable;
begin
  var index: Integer := 345;
  ShowMessage(index.ToString);
end;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.