Wieso kommt dieser Compilerhinweis?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1838
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Wieso kommt dieser Compilerhinweis?

Beitrag von fliegermichl »

Code: Alles auswählen

program Project1;
type
  TPoint = record
    x, y : integer;
  end;

var Points : array of TPoint;

begin
  SetLength(Points, 3);
  Points[0].x := 10;
  Points[0].y := 10;
  Points[1].x := 20;
  Points[1].y := 20;
  Points[2].x := 30;
  Points[2].y := 30;
end. 
Da bekomme ich den Hinweis

Code: Alles auswählen

project1.lpr(10,19) Hint: Variable "Points" of a managed type does not seem to be initialized
SetLength macht doch eben diese Initialisierung.

Mathias
Beiträge: 7358
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Wieso kommt dieser Compilerhinweis?

Beitrag von Mathias »

So sollte die Warnung weg sein,

Code: Alles auswählen

var Points : array of TPoint = nil;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1838
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Wieso kommt dieser Compilerhinweis?

Beitrag von fliegermichl »

Mathias hat geschrieben: Di 15. Sep 2026, 13:29 So sollte die Warnung weg sein,

Code: Alles auswählen

var Points : array of TPoint = nil;
Ja natürlich. Sollte der Compiler nicht aber "wissen", dass SetLength eben diese Initialisierung durchführt?

Benutzeravatar
Zvoni
Beiträge: 744
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz/FPC fixes)
CPU-Target: 64Bit
Wohnort: BW

Re: Wieso kommt dieser Compilerhinweis?

Beitrag von Zvoni »

Mathias hat geschrieben: Di 15. Sep 2026, 13:29 So sollte die Warnung weg sein,

Code: Alles auswählen

var Points : array of TPoint = nil;
Aber dann widerspricht sich die Dokumentation irgendwie
https://www.freepascal.org/daily/doc/rt ... types.html
Are implicitly initialized at the beginning of their scope. Usually this means the memory area reserved for them is zeroed out.
*schnipp*
Dynamic arrays
Are reference counted.
Was nu?
Wird das Ding jetzt implizit initialisiert oder nicht?

Oder gehts eher darum, dass die Variable selbst eigentlich ein Zeiger ist?
Weil nur dann ergibt das was Mathias geschrieben hat Sinn
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 7447
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Wieso kommt dieser Compilerhinweis?

Beitrag von af0815 »

... RTFM ... dann wird es undurchsichtig. Zvoni hat da recht.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Warf
Beiträge: 2330
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Wieso kommt dieser Compilerhinweis?

Beitrag von Warf »

Die Warnungen für managed variablen sind etwas irreführend.
Managed typen werden (fast) immer initialisiert das muss man nicht manuell machen, im Gegenteil, bei managed records kann eine Initialisierung sogar beliebig Komplexität hinzufügen. In FPC 3.2.x ist die Initialisierung über Default allerdings auch broken das wenn man die warning loswerden will man potentiell mehr kaputt macht.

Die Ausnahme für die Initialisierung (oben das "fast immer") ist für dynamische arrays und strings die das result einer Funktion sind, diese werden nicht initialisiert.

Code: Alles auswählen

function foo: String;
begin
  Result += 'A';
end;

var s: String;
begin
  s:=foo; // A
  s:=foo; // AA
  s:=foo; // AAA
  writeLn(s);
end.
Managed records werden hingegen korrekt initialisiert.

Bzg SetLength als Initialisierung, der Grund dafür ist das SetLength den parameter als "var" und nicht als "out" behandelt.

PascalDragon
Beiträge: 1053
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Wieso kommt dieser Compilerhinweis?

Beitrag von PascalDragon »

fliegermichl hat geschrieben: Di 15. Sep 2026, 13:09 Da bekomme ich den Hinweis

Code: Alles auswählen

project1.lpr(10,19) Hint: Variable "Points" of a managed type does not seem to be initialized
SetLength macht doch eben diese Initialisierung.
Ich bin auch kein Fan von diesem Hinweis außer für Result-Variablen (bei denen dies tatsächlich relevant ist), aber fpk ist da anderer Ansicht... 🙄
FPC Compiler Entwickler

Benutzeravatar
kupferstecher
Beiträge: 445
Registriert: Do 17. Nov 2016, 11:52

Re: Wieso kommt dieser Compilerhinweis?

Beitrag von kupferstecher »

PascalDragon hat geschrieben: Fr 18. Sep 2026, 21:12 [...] außer für Result-Variablen (bei denen dies tatsächlich relevant ist), [...]
Warum ist das für Result-Variablen relevant? Managed-Typen werden doch initialisiert, wenn sie das erste Mal in Scope kommen, wenn sie ein Funktionsergebnis sind also spätestens in der aufrufenden Funktion. Genauso bei var-Parametern.

Wenn es nur darum geht, dass man kein Result zugewiesen hat, müsste doch die Fehlermeldung "Function result does not seem to be set" kommen?

Warf
Beiträge: 2330
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Wieso kommt dieser Compilerhinweis?

Beitrag von Warf »

kupferstecher hat geschrieben: Sa 19. Sep 2026, 12:38 Warum ist das für Result-Variablen relevant? Managed-Typen werden doch initialisiert, wenn sie das erste Mal in Scope kommen, wenn sie ein Funktionsergebnis sind also spätestens in der aufrufenden Funktion. Genauso bei var-Parametern.

Wenn es nur darum geht, dass man kein Result zugewiesen hat, müsste doch die Fehlermeldung "Function result does not seem to be set" kommen?
Siehe mein Beispiel oben

PascalDragon
Beiträge: 1053
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Wieso kommt dieser Compilerhinweis?

Beitrag von PascalDragon »

kupferstecher hat geschrieben: Sa 19. Sep 2026, 12:38
PascalDragon hat geschrieben: Fr 18. Sep 2026, 21:12 [...] außer für Result-Variablen (bei denen dies tatsächlich relevant ist), [...]
Warum ist das für Result-Variablen relevant? Managed-Typen werden doch initialisiert, wenn sie das erste Mal in Scope kommen, wenn sie ein Funktionsergebnis sind also spätestens in der aufrufenden Funktion. Genauso bei var-Parametern.
Siehe Warfs Beispiel.
kupferstecher hat geschrieben: Sa 19. Sep 2026, 12:38 Wenn es nur darum geht, dass man kein Result zugewiesen hat, müsste doch die Fehlermeldung "Function result does not seem to be set" kommen?
Das ist kein Fehler, sondern eine Warnung.
FPC Compiler Entwickler

Benutzeravatar
kupferstecher
Beiträge: 445
Registriert: Do 17. Nov 2016, 11:52

Re: Wieso kommt dieser Compilerhinweis?

Beitrag von kupferstecher »

Warf hat geschrieben: Di 15. Sep 2026, 16:38

Code: Alles auswählen

function foo: String;
begin
  Result += 'A';
end;
OK, so ist das gemeint. Das Verhalten hätte ich so mehr oder weniger erwartet. Result ist in dem Fall ja in gewisser Weise schon initialisiert, aber eben nicht innerhalb der Funktion. Dem Begriff Initialisieren kommt da m.E. eine Art doppelte Bedeutung zu. Einerseits für das Initialisieren der Struktur mit dem Reference-Count, das der Compiler immer machen muss um konsistente Daten zu haben (aber eben nicht unbedingt innerhalb der Funktion selbst). Und andererseits für das Zuweisen eines vordefinierten Wertes (hier in der Funktion). Ersteres beinhaltet dann auch das Zuweisen eines konkreten Wertes.

Das Problem an der Warnung "[...] of a managed type does not seem to be initialized" seh ich darin, dass man den Eindruck bekommen könnte, dass der Managed-Typ kaputt/korrumpiert ist, wenn er nicht (sauber) initialisiert ist. Was natürlich nicht der Fall ist.

Warum wird vom Compiler nicht am Anfang der Funktion das Result automatisch initialisiert? Aus Performance-Gründen?
PascalDragon hat geschrieben: Mo 21. Sep 2026, 22:56 Das ist kein Fehler, sondern eine Warnung.
Ja, war unsauber formuliert, danke für die Korrektur.

Benutzeravatar
Zvoni
Beiträge: 744
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz/FPC fixes)
CPU-Target: 64Bit
Wohnort: BW

Re: Wieso kommt dieser Compilerhinweis?

Beitrag von Zvoni »

kupferstecher hat geschrieben: Di 22. Sep 2026, 12:19 Warum wird vom Compiler nicht am Anfang der Funktion das Result automatisch initialisiert? Aus Performance-Gründen?
Weil am Ende des Tages die Variable für ein dynamisches Array bzw. eine (Result-) Variable für einen String unter der Haube eben doch ein Zeiger ist?
Wenn ein Result-String ja noch unbekannt ist, mit was soll es denn initialisiert werden?
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Warf
Beiträge: 2330
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Wieso kommt dieser Compilerhinweis?

Beitrag von Warf »

Naja die (etwas übervereinfacht) simple Antwort ist das Result einfach ein versteckter Var parameter ist.
Das stimmt aber auch nur so halb. Für managed records wird bei jedem Funktionsaufruf unter der haube ein neues temporäres Objekt erzeugt und frisch initialisiert. Innerhalb der funktion ist es zwar immernoch nur ein var parameter aber eben auf das temporäre Objekt nicht auf das tatsächlichr Ziel.

Das sind aber undokumentierte Compiler Internas und sollte man sich nicht drauf verlassen. Daher: Funktionsergebnisse immer initialisieren, auch wenns wehtut (z.b. performance)

Das die result variable außerhalb initialisiert wird ist aber mMn auch keine gute Erklärung, denn eigentlich existiert sie ja nur im scope der Funktion. Klar kann man sagen das wenn ich das funktionsergebnis einer variable zuweise die quasi nur als var übergeben wird, aber Funktionen sind ja noch deutlich mächtiger.
Im Gegensatz zu einem var parameter kann ich das Funktionsergebnis einfach ignorieren, oder als teil einer expression benutzen:

Code: Alles auswählen

foo; // ignoriert Ergebnis
WriteLn(foo+'A');
In diesem fall existiert das Result Objekt außerhalb eigentlich nicht, zumindest nicht als Pascal Objekt. Klar erzeugt der Compiler unter der Haube da was temporäres, aber aus einer reinen Sprachebenen sicht, gibt es kein Objekt was initialisiert wird

Benutzeravatar
kupferstecher
Beiträge: 445
Registriert: Do 17. Nov 2016, 11:52

Re: Wieso kommt dieser Compilerhinweis?

Beitrag von kupferstecher »

Zvoni hat geschrieben: Di 22. Sep 2026, 13:13
kupferstecher hat geschrieben: Di 22. Sep 2026, 12:19 Warum wird vom Compiler nicht am Anfang der Funktion das Result automatisch initialisiert? Aus Performance-Gründen?
Weil am Ende des Tages die Variable für ein dynamisches Array bzw. eine (Result-) Variable für einen String unter der Haube eben doch ein Zeiger ist?
Wenn ein Result-String ja noch unbekannt ist, mit was soll es denn initialisiert werden?
Ich seh es gerade andersrum: Weil es ein Zeiger ist, den der Code innerhalb der Funktion benutzen kann, kann darin kein beliebiger Wert stehen. Entweder es ist ein leerer Zeiger, also nil, oder er zeigt auf eine Instanz, die auch tatsächlich vorhanden sein muss. in diesem Sinne kann die Result-Variable also nicht uninitialisiert sein. Aber es kann natürlich der "falsche" Wert drin stehen.

Im Hinblick auf Fehlertoleranz, denke ich, wäre es sinnvoll, den Wert auf null/nil zu initialisieren. In den meisten Fällen, wo der Programmierer explizit per Code initialisiert, kann das dann sowieso wegoptimiert werden. Das soll nicht heißen, dass es dann keine Warnung bräuchte.

Warf hat geschrieben: Di 22. Sep 2026, 14:04 Für managed records wird bei jedem Funktionsaufruf unter der haube ein neues temporäres Objekt erzeugt und frisch initialisiert. Innerhalb der funktion ist es zwar immernoch nur ein var parameter aber eben auf das temporäre Objekt nicht auf das tatsächliche Ziel.
So sollte es auch sein, denke ich. So kann man auch als Parameter und als Result die gleiche Variable übergeben, ohne dass es kracht (Ich kann mich hier aber täuschen).

Warf hat geschrieben: Di 22. Sep 2026, 14:04 Das sind aber undokumentierte Compiler Internas und sollte man sich nicht drauf verlassen.
Ja, einerseits muss man die Internas kennen, siehe Zeile davor, andererseits kann man dann Dinge auch leicht missverstehen, die sonst klarer wären. Manchmal ist mir Freepascal in der Hinsicht zu kompliziert, es gibt so viele Spezialfälle wie den hier diskutierten, welche Parameter werden als Wert übergeben (kopiert) und welche per Referenz übergeben. Da sollte man den Mechanismus der Result-Übergabe eines Record wieder kennen.

himitsu
Beiträge: 2
Registriert: Di 22. Sep 2026, 11:40

Re: Wieso kommt dieser Compilerhinweis?

Beitrag von himitsu »

= nil
Sollte eigentlich nicht nötig sein, da dieser Speicherbereich, der globalen Variablen, grundsätzlich mit Nullen initialisiert ist.
Result +=
Per se ist der Result ja initialisiert, für managed Typen, drum kommt da keine Warnung.
OK, es ist hier beim Aufrufer initialisiert worden, denn "dieses" Result wird intern als Var-Parameter implementiert. (wenn managed oder der Typ größer als ein Pointer)

Rein "logisch" sollte der Compiler, bei solchen Result, aber "vergessen", dass es bereits (extern) initialisiert wurde, damit dennoch diese Warnung angezeigt wird. (ob es hier auch beim SetLength warnen soll, darüber darf man streiten)

Antworten