Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi boolsche Variable abfragen, aber wie genau(Anfängerfrage...) (https://www.delphipraxis.net/76022-boolsche-variable-abfragen-aber-wie-genau-anfaengerfrage.html)

juergen 28. Aug 2006 21:29


boolsche Variable abfragen, aber wie genau(Anfängerfrage...)
 
Hallo zusammen,
"irgendwann" und "irgendwo" hatte ich hier in den letzten Tagen etwas gelesen, wo darauf hingewiesen wurde, dass man boolsche Variablen nicht direkt abfragen soll:
Delphi-Quellcode:
if MyBoolVar = true then
  begin...
(meine bisherige Verfahrensweise)

sondern einfach:

Delphi-Quellcode:
if MyBolVar then
  begin...
Irgendwie ging mir das ganze nicht mehr aus dem Kopf, allzumal ich (leider nicht nachvollziehbar) ein einziges Mal in einem kl.Prog von mir einen für mich bis heute nicht nachvollziehbaren Fehler hatte/habe...
Im Nachhinein könnte das ganze sogar mit der Abfrage einer Varibale zu tun haben, welche ich im OnCreate der Hauptform abfrage.

Ist es nun Gesetz eine boolsche Variable nicht direkt abzufragen und wenn ja warum?
Muss eine boolsche Variable überhaupt initialisiert werden?

Schon mal Danke für die Antworten!

Bernhard Geyer 28. Aug 2006 21:36

Re: boolsche Variable abfragen, aber wie genau(Anfängerfrage
 
In Delphi/Pacal oder anderen Sprachen die einen vernünftigen Boolean-Typ haben ist es egal.
Gefährlich kann es in C/(C++ glaube ich auch nicht) werden da es dort ja keinen Boolean-Typ gibt und TRUE/FALSE nur 2 Integer-Konstanten sind und in jedem Projekt so ziemlich 100 mal Boolean definiert wird.

Sinnvollerweise sollte es so sein:

Code:
  FALSE = 0;
  TRUE != FALSE;
oft wird aber auch

Code:
  FALSE = 0;
  TRUE = 1;
genommen und wenn dann eine Funktion als Boolean-Wert 2 zurückgibt steht man vor einem Problem

mkinzler 28. Aug 2006 21:36

Re: boolsche Variable abfragen, aber wie genau(Anfängerfrage
 
Das Vergleichen einer Boolean-Vraibale mit True oder False ist unnötig, da ein Vergleich auch ein Boolean als Ergebnis liefert.

Delphi-Quellcode:
if MyBoolVar = true
wird dann zu
Delphi-Quellcode:
if True=True
was das selbe wie
Delphi-Quellcode:
if True
ist.

Zitat:

Muss eine boolsche Variable überhaupt initialisiert werden?
Ja.

DGL-luke 28. Aug 2006 21:45

Re: boolsche Variable abfragen, aber wie genau(Anfängerfrage
 
initialisieren? :shock:

Du musst gar nix initilisieren. eine nicht initialisierte variable solltest du aber immer als undefiniert betrachten.

Den vergleich "SomeBool = true" sollte man deswegen nicht machen, weil es ziemlich viele verschiedene Booleans "da draussen" gibt und evtl. eben irgendwann DIESER Vergleich fehlschlägt, obwohl die Variable auf einem zulässigen True-Wert steht und der normale Vergleich auch dieses Ergebnis hätte. True hat nänmlich einen bestimmten Wert, nämlich 1, während alle Werte außer False (0) per definitionem als True auszuwerten sind. Dannn sind die Aussagen "Das Flag ist gesetzt" und "Das Flag hat den Wert True" nicht äquivalent.

Sharky 29. Aug 2006 06:30

Re: boolsche Variable abfragen, aber wie genau(Anfängerfrage
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hai juergen,

hier einmal ein Beispiel was passieren kann wenn man auf xxx = True prüft. (Das ist natürlich eine Vergewaltigung einer Bool-Variablen was ich da macht *g*)
Delphi-Quellcode:
var
  myBool: Boolean;

procedure TDemo_Form.FormCreate(Sender: TObject);
begin
  myBool := False;
  SetLabelText;
end;

procedure TDemo_Form.SetLabelText;
begin
  if (myBool) then
  begin
    Label1.Caption := 'myBool ist True';
  end
  else
  begin
    Label1.Caption := 'myBool ist nicht True';
  end;

  if (myBool = True) then
  begin
    Label2.Caption := 'myBool ist True';
  end
  else
  begin
    Label2.Caption := 'myBool ist nicht True';
  end;

  Label3.Caption := Format('myBool hat den "Wert" %d', [Integer(myBool)]);
end;

procedure TDemo_Form.SpinButton1DownClick(Sender: TObject);
begin
  if (myBool) then
    Dec(myBool);
  SetLabelText;
end;

procedure TDemo_Form.SpinButton1UpClick(Sender: TObject);
begin
  Inc(myBool);
  SetLabelText;
end;

uligerhardt 29. Aug 2006 07:54

Re: boolsche Variable abfragen, aber wie genau(Anfängerfrage
 
Mal abgesehen von den Fehlermöglichkeiten ist die einfache Variante IMHO auch die natürlichere. Du sagst doch "Wenn meine Form den Fokus hat, dann..." und nicht "Wenn es wahr ist, dass meine Form den Fokus hat, dann...". Folglich
Delphi-Quellcode:
if MyForm.IsFocused then
statt
Delphi-Quellcode:
if MyForm.IsFocused = True then
.

Uli.

Der_Unwissende 29. Aug 2006 08:33

Re: boolsche Variable abfragen, aber wie genau(Anfängerfrage
 
Zitat:

Zitat von juergen
Muss eine boolsche Variable überhaupt initialisiert werden?

Hi,
ich denke hier sollte nocheinmal klar gesagt werden, dass du boolsche Variablen immer initialisieren solltest! Hier wurde zwar schon gesagt, dass die sonst undefiniert sind, aber die Konsequenzen sollten einem auch klar sein.
Instanzvariablen (also Variablen die zu einer Klassen-Instanz gehören) werden immer initialisiert. Hast du hier einen Boolschen Wert ist der auch initialisiert, die Frage ist also nur True oder False?
Da man mit boolschen Werten i.d.R. einen Zustand anzeigt und man diesen wiederum für den Programmstart leicht festlegen kann, sollte man hier die Variable auch im Konstruktor initialisieren.
Verzichtet man darauf, schafft man sich einen Fehler der nicht immer leicht zu finden ist.

Das Problem lässt sich sogar verallgemeinern! Du solltest jede Variable initialisieren! Das der Wert einer Variablen nicht definiert ist störrt dein Programm sehr wenig. Legst du eine lokale Variable an, so wird einfach ein Speicherbereich genommen, der gerade frei ist, in den diese Variable reinpasst. Natürlich wird der gleiche Speicher immer wieder mal von irgendeinem Programm benutzt (darum kümmert sich Windows). Wird ein Programm / eine Prozedur beendet, werden die verwendeten Speicherbereiche nur als frei markiert. Das heißt die alten Werte stehen hier immer noch.
Ja, dein Programm macht auch das, was es immer tut: Es nimmt den Speicher und interpretiert den vorgefundenen Wert. Mit etwas Glück startest du das Programm und es kracht. Mit etwas Pech passiert nichts und alles läuft wie erwartet.
Gut, letzteres klingt erstmal gar nicht so schlimm. Das Problem ist nur, du hast ein Programm das nicht mehr terminiert. Irgendwann (gerne beim Kunden) ist der Speicher mal mit einem falschen Wert initialisiert, was dann? Hier kann es zu einer Exception kommen, aber auch zu einer Schleife die einfach mal 2.000.000.000 Durchläufe mitmacht oder zu allem anderen.
Hier den Fehler zu finden ist auch um einiges schwieriger, da es ein semantischer Fehler ist, der sich nicht mal ohne weiteres reproduzieren lässt. Je nachdem welcher Wert gerade im entsprechenden Speicher steht geht alles gut oder es treten ganz verschiedene Fehler auf.

Delphi-Quellcode:
procedure doFoo;
var i : Integer;
begin
  // ganz schlecht
  // i wird nicht initialisiert, könnte auch -2^{31} sein
  // das wären eine ganze Menge durchläufe!
  while (i < 10) do
  begin
  end;
 
  // besser:
  i := 0;
  while (i < 10) do
  begin
  end;

  // oder
  for i := 0 to 10 do
  begin
  end;
end;

procedure doMoreFoo;
var bitmap : TBitmap;
begin
  if assigned(Bitmap) then
  begin
    // tja, sehr hohe Chance hier zu landen
    // natürlich wurde die Bitmap nicht angelegt!
    // aber assigned prüft ob die Referenz <> nil ist
    // nil ist dabei die Adresse 0x00000000
    // Das heißt es gibt 2^{32} - 1 Möglichkeiten die ungleich 0 sind.
    // da auf die 0 zu hoffen ist schlecht!
  end;
end;
Deshalb ist die goldene Regel alles zu initialisieren, was man verwendet! Das gilt insbesondere dann auch wieder, wenn du eine Variable freigibst, die noch gelesen werden könnte (und damit implizit für alle Instanzvariablen, die eine Klasse als Datentyp haben). Wenn du diese mittels Free freigibst, dann wird auch schön der Speicher als frei markiert, in dem die Variable lag. Die Referenz die du als Variable speicherst, die wird nicht verändert. Für eine solche Variable ist es nicht möglich zu sagen, ob sie gültig ist oder nicht. Genaugenommen musst du denken die ist gültig. Die zeigt dann auf einen freien (oder anders verwendeten) Speicher und das geht auch nicht gut! Deshalb beim freigeben solcher Variablen FreeAndNil verwenden.

Delphi-Quellcode:
type
  TMyClass = class(TObject)
    private
      FBitmap : TBitmap;
    protected
      procedure createBitmap;
      procedure doFoo;
      procedure FreeBitmap;
  end;

...

procedure TMyClass.createBitmap;
begin
  // Fehler1 : nicht freigeben der alten Bitmap!
  self.FBitmap := TBitmap.Create;
  self.FBitmap.Width := 512;
  self.FBitmap.Height : 512;
  self.FBitmap.PixelFormat := pf32Bit;
 
  // so, würde zweimal hintereinander createBitmap aufgerufen werden,
  // würde die erste Instanz bis zum Programmende im Speicher liegen
  // das heißt man verschwendet hier 4 Byte * 512 * 512, also ein kleines MByte
  // wenn ich diese Operation jetzt mehrfach aufrufe....


  // besser:
  // erst aufräumen
  FreeAndNil(self.FBitmap);

  // dann neu anlegen
  self.FBitmap := TBitmap.Create;
  self.FBitmap.Width := 512;
  self.FBitmap.Height : 512;
  self.FBitmap.PixelFormat := pf32Bit;
end;

procedure TMyClass.FreeBitmap;
begin
  // 1:
  self.FBitmap.Free;

  // 2:
  FreeAndNil(self.FBitmap);
end;

procedure TMyClass.doFoo;
begin
  // mögliche Probleme nach Aufruf von
  // FreeBitmap
  if assigned(self.FBitmap) then
  begin
    // Probleme variieren zwischen 1 und 2
    // 2 funktioniert immer wie gewünscht!

    // bei 1 wird nur der Speicher auf den self.FBitmap zeigt freigegeben
    // die Adresse, die implizit in self.FBitmap steht bleibt erhalten
    // wurde hier also mittel createBitmap einmal eine gültige Adresse zugewiesen,
    // so würde diese Bedingung wahr sein

    with self.FBitmap do
    begin
      ...
      // dies würde jetzt für 1 zu einem Problem werden!
      // es gibt schließlich keine Bitmap mehr!
    end;
  end;
end;

juergen 29. Aug 2006 18:54

Re: boolsche Variable abfragen, aber wie genau(Anfängerfrage
 
Hallo zusammen,
für die ganzen Antworten: allen herzlichen Dank!!!

Mir ist eines klar gewurden:
ich muss unbedingt meine Einstellung zur boolschen Variable ändern! :mrgreen:
Das Beispiel von Sharky ist hier (für mich) sehr anschaulich.
Schnell erkennt man, dass jeder Wert einer boolschen Varibale <> 0 dann auch immer true ist und eine Prüfung impliziet auf
(myBool = True) hier einen falschen Wert liefert.

@ Der_Unwissende
du weißt schon, dass deine ausführlichen Beschreibungen auch etwas "Angst" in mir geweckt haben? :zwinker:
Bis jetztb hatte ich "Zahlen"- und Stringvariablen auch immer schön initialisiert.
Auch evtl. vorhandene Variablen die eine Klasse als Datentyp haben, hatte ich immer schön per FreeAndNil freigegeben.
Die boolschen Variablen hatte ich leider nicht immer initialisiert...
Da werde ich einiges nacharbeiten.

Grüße und einen schönen Abend!
Jürgen


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:59 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz