Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Tutorials und Kurse (https://www.delphipraxis.net/36-tutorials-und-kurse/)
-   -   Delphi Über den Umgang mit Boolean (https://www.delphipraxis.net/57121-ueber-den-umgang-mit-boolean.html)

Brüggendiek 16. Nov 2005 06:50


Über den Umgang mit Boolean
 
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo!

Nun möchte ich mich auch mal an einem kurzen Tutorial versuchen

Über den Umgang mit Boolean

Ein Tutorial von Dietmar Brüggendiek


Die Beispiele wurden mit Delphi 5 Standard geschrieben.

Wenn ich mich in den Delphi-Foren so umschaue, finde ich immer wieder Sources, die - gelinde gesagt - nicht so ganz richtig sind.

Man findet häufig Folgendes:
Delphi-Quellcode:
if BoolVar=true then
  IrgendWas;
:wiejetzt: Was soll das denn werden, wenn es fertig ist? Die Syntax ist da doch ganz eindeutig:
Delphi-Quellcode:
IF <logischer Ausdruck> THEN
  anweisung [ELSE anweisung];
Ein logischer Ausdruck kann dabei ein Vergleich sein, z.B.
Delphi-Quellcode:
if IntVar=5 then
  IrgendWas;
Es kann aber auch ein logischer Wert (Variablentyp Boolean) direkt da stehen:
Delphi-Quellcode:
if BoolVar then
  IrgendWas;
oder auch eine Verknüpfung von logischen Ausdrücken.

Der Vergleich "BoolVar=True" kann sogar kräftig in die Hose gehen!
Bei einem normalen Boolean ist es so, daß "True" den Ordinalwert "1" hat. Bei ByteBool, WordBool und LongBool hat "True" normalerweise den Ordinalwert "-1".
Einige Windows-API-Aufrufe liefern ein Ergebnis vom Typ BOOL. Dabei gilt für den einen Fall "Ergebnis=0" und im anderen Fall "Ergebnis<>0". Ein Wert ungleich 0 muß aber nicht unbedingt 1 oder -1 sein! Das Ergebnis: die Variable ist bei <>0 möglicherweise weder true noch false!
Ein Vergleich mit "false" ist nur überflüssig, führt aber nicht zu fehlerhaftem Programmverhalten.
In einem IF-Statement wird jedoch jeder Wert <> 0 als True betrachtet.


Mal ein Beispiel:

Schreiben wir eine Funktion, die uns einen Integer aus einem String liest und eine Fehler-Variable setzt, wenn der String keine gültige Zahl enthält. Dazu verwenden wir das gute alte "Val" - da brauchen wir uns nicht um Exceptions zu kümmern und sparen Aufwand und Rechenzeit.
Delphi-Quellcode:
function GetInt(const aSatz:string; var aFehler:Boolean):Integer;
var Code:Integer;
begin
  Val(aSatz, Result, Code);
  aFehler:=Boolean(Code);
end;
Die Zuweisung an aFehler ist zwar nicht empfohlen, aber sie funktioniert! Code enthält 0, wenn die Umwandlung möglich war oder die Position des Fehlers im String. Dadurch ist der Ordinalwert der Boolean-Variablen entweder =0 (false) oder <>0 (gilt als true). Nutzen wir diese Funktion jetzt mal auf die falsche Weise:
Delphi-Quellcode:
procedure Test(const aSatz:string);
var
  Wert:Integer;
  Fehler:Boolean;
begin
  wert:=GetInt(aSatz, Fehler);
  if Fehler=true then
    ShowMessage(aSatz + ': Eingabefehler!') else
  if Fehler=false then
    ShowMessage(aSatz + ': Wert: '+IntToStr(Wert)) else
    ShowMessage(aSatz + ': Hupps!');
end;
Wenn wir das Ganze nun so aufrufen:
Delphi-Quellcode:
Test('123');
Test('a234');
Test('1asfg');
bekommen wir nacheinander die Meldungen:
Code:
123: Wert: 123
a234: Eingabefehler!
1asfg: Hupps!
Klar, im 3. Fall ist der Fehler in Position 2 und 2 ist nicht gleich Ord(True) !

Kaum macht man's richtig, funktioniert es auch schon! Wir ersetzen die Prozedur "test" durch diese:
Edit: Uuups - das war doch der falsche Code - hier muß ja auch der 3. Fall hin!
Delphi-Quellcode:
procedure Test(const aSatz:string);
var
  Wert:Integer;
  Fehler:Boolean;
begin
  wert:=GetInt(aSatz, Fehler);
  if Fehler then
    ShowMessage(aSatz + ': Eingabefehler!') else
  if not Fehler then
    ShowMessage(aSatz + ': Wert: '+IntToStr(Wert)) else
    ShowMessage(aSatz + ': Hupps!');
end;
und erhalten das richtige Ergebnis:
Code:
123: Wert: 123
a234: Eingabefehler!
1asfg: Eingabefehler!
Wie oben schon erwähnt, gibt es diese Rückgabewerte bei Windows-API-Aufrufen. Das etwas haarige Beispiel ist also gar nicht so weit hergeholt.


Was soll nun das schon wieder werden, wenn's fertig ist?
Delphi-Quellcode:
if BoolVar then
begin
end else
  Irgendwas;
Bei solchem Gestümpere rollen sich mir die Fußnägel auf! Warum denn der leere Block? Achja, es soll was getan werden, wenn die Variable nicht true ist. Aber vielleicht sollte man sich ja mal mit den Boolean-Operatoren beschäftigen. Da könnte man herausfinden, daß es NOT gibt!
Delphi-Quellcode:
if not BoolVar then
  IrgendWas;
bewirkt dasselbe, ist kürzer und für andere Programmierer leichter zu lesen.
(Anmerkung: sollte das Programm noch nicht fertig sein und der Block später noch gefüllt werden, habe ich nichts gesagt. Aber dann sollte man doch einen Kommentar setzen, daß hier noch was fehlt!)


Weiter geht es in unserer beliebten Reihe: "Warum Einfach wenn's auch kompliziert geht?" mit Folgendem:
Delphi-Quellcode:
if IntVar=5 then
  BoolVar:=true else
  BoolVar:=false;
Der Ausdruck "IntVar=5" ist doch schon ein Boolean und kann der BoolVar direkt zugewiesen werden! Wir schreiben also
Delphi-Quellcode:
BoolVar:=IntVar=5;
und gut ist!
Im umgehehrten Fall müssen wir auch nicht mit
Delphi-Quellcode:
if IntVar=5 then
  BoolVar:=false else
  BoolVar:=true;
arbeiten. Da hilft
Delphi-Quellcode:
BoolVar:=not (IntVar=5);
Allerdings: Die Klammern darf man hier nicht vergessen!


Auswertung boolscher Ausdrücke


Bei Boolean-Ausdrücken kann es natürlich vorkommen, daß das Ergebnis vorzeitig feststeht:
Delphi-Quellcode:
if (IntVar1=5) or (IntVar2=9) or (IntVar3=567) then
  IrgendWas;
Wenn die 1. Variable 3, die 2. 9 und die 3. 567 ist, braucht der letzte Vergleich nicht mehr ausgeführt werden, denn es ist ja schon ein Ausdruck wahr.
Standardmäßig führt Delphi hier eine Optimierung durch, indem die Auswertung dann abgebrochen wird, wenn das Ergebnis bereits feststeht. Das kann man aber abschalten. Dazu gibt es den Compilerschalter $B bzw. $BOOLVAR. Die verkürzte Auswertung von Boolean-Ausdrücken führt aber zu einer weiteren bösen Falle:
Delphi-Quellcode:
if (Length(StringVar)>=5) and (StringVar[5]='x') then
  IrgendWas;
ist eine ganz gefährliche Sache. Bei optimiertem Boolean wird der 2. Teil nicht mehr ausgewertet; ohne Optimierung jedoch ergibt sich bei AnsiString die Situation, daß der Index außerhalb des Wertebereichs liegen kann.
Solange man in seiner Unit/Komponente den B-Compilerschalter richtig einstellt, sollte beim Austausch von Quellcode nichts passieren. Wenn man sich jedoch auf die Einstellung des Compilers verläßt, ist man verlassen und erhält dann vom Anwender Rückmeldungen, daß das Ganze "manchmal" fehlerhaft läuft.

SIMULA67 kennt bedingte Ausdrücke. Damit könnte man das Problem sinngemäß so lösen:
Code:
IF (IF Length(string_var) >= 5 THEN False ELSE string_var[5] = 'x') THEN
    irgend_was;
Das Beispiel ist syntaktisch nicht ganz richtig, aber in SIMULA habe ich schon lange nicht meht programmiert. Außerdem ist dieser Sprachmix für Delphi-Programierer leichter zu verstehen.

In Delphi sollte man hier nicht sparen:
Delphi-Quellcode:
if Length(StringVar)>=5 then
  if StringVar[5]='x' then
    IrgendWas;
und man ist für alle Fälle gerüstet.
Man kann die Auswertung ja in einer Funktion kapseln.


Sinn und Unsinn der verkürzten Auswertung


Im obigen Beispiel erscheint die verkürzte Auswertung sinnvoll. Was ist aber, wenn mehrere Funktionen aufgerufen werden, die jeweils noch etwas Weitergehendes erledigen?

Ein Beispiel: Berechnen des Rauminhaltes eines Quaders.
Wir lesen Länge, Breite und Höhe als Integer-Werte aus 3 TEdit. Wenn ein Feld kein Integer enthält, soll das zum TEdit gehörende TLabel rot eingefärbt werden, um den Fehler anzuzeigen. Werden alle Werte korrekt eingegeben, wird ein Ergebnisfeld auf den Rauminhalt gesetzt.
Delphi-Quellcode:
procedure TForm1.bRechnenClick(Sender: TObject);
var Laenge, Breite, Hoehe: Integer;

begin
  if LeseEingabe(lLaenge, Laenge) or LeseEingabe(lBreite, Breite) or
    LeseEingabe(lHoehe, Hoehe) then
    lErgebnis.Caption:='Fehler!' else
    lErgebnis.Caption:=IntToStr(Laenge*Breite*Hoehe);

{
Das erste fehlerhafte Edit oder das erste Edit aktivieren
}
  if lLaenge.Color<>Color then
    TEdit(lLaenge.FocusControl).Setfocus else
  if lBreite.Color<>Color then
    TEdit(lBreite.FocusControl).Setfocus else
  if lHoehe.Color<>Color then
    TEdit(lHoehe.FocusControl).Setfocus else
    eLaenge.Setfocus;
end;

function TForm1.LeseEingabe(const aLabel: TLabel; var aWert: Integer): Boolean;
var Code: Integer;
begin
  Val(TEdit(aLabel.FocusControl).Text, aWert, Code);
  Result:=Code<>0;
  if Result then
    aLabel.Color:=clRed else
    aLabel.Color:=Color;
end;
Haben wir das Kurzschlußverfahren eingeschaltet (B- oder BOOLVAR OFF), wird nur der erste Fehler gemeldet. Bei vollständiger Auswertung (B+ oder BOOLVAR ON) werden alle Fehler gemeldet.

Im Anhang ist das vollständige Projekt mit gleichzeitiger Auswertung in beiden Varianten. Glücklicherweise ist der B-Schalter lokal, kann also in einer Datei beliebig oft gesetzt werden. Die linke Spalte wird mit B+, die rechte mit B- ausgewertet. Man sieht bei Eingabefehlern in mehreren Feldern schön den Unterschied.
Von der Ergonomie her sollte natürlich das Verhalten der linken Spalte benutzt werden.

Für Benutzer älterer Compiler habe ich das Formular im älteren Verfahren (also nicht als Text) gespeichert. Wer nicht compilieren will, kann sich auch die Echse laden.
Das Ganze ist so einfach wie möglich gehalten - es soll ja nur das Prinzip gezeigt werden.

Anmerkung: Bitte nicht über die fehlende Typprüfung beim Cast nach TEdit meckern! Das Ganze wird zur Designzeit festgelegt, so daß Fehler wie fehlendes FocusControl oder ein falsches Feld im FocusControl bereits beim ersten Test auffallen werden. Wer natürlich nach dem Motto vorgeht: "Es compiliert, wir können es ausliefern", hat Pech gehabt :mrgreen:

Gruß

Dietmar Brüggendiek

Robert Marquardt 16. Nov 2005 07:23

Re: Über den Umgang mit Boolean
 
Da ist noch eine Falle.
Delphi-Quellcode:
  aFehler:=Boolean(Code);
Hier verlaesst man sich darauf das Compilermagic es schon richten wird.
Besser ist
Delphi-Quellcode:
  aFehler := Code <> 0;
Das ist auch deutlicher in seiner Aussage.

Zusatzlich moechte ich noch die wirklich schlimme Praxis des leeren else erwaehnen.
Da gebe ich mal kein Beispiel, damit es keiner nachmacht.

Daniel G 16. Nov 2005 12:02

Re: Über den Umgang mit Boolean
 
Zitat:

Zitat von Robert Marquardt
Zusatzlich moechte ich noch die wirklich schlimme Praxis des leeren else erwaehnen.
Da gebe ich mal kein Beispiel, damit es keiner nachmacht.

Da stellen wir uns jetzt mal janz doof:

Was bringt denn bitte ein leeres else?

//Edit: Hab' nachgedacht:
Das waren die Leute, die not nich kennen, oder? :stupid:
Schwachsinn...

Robert Marquardt 16. Nov 2005 12:58

Re: Über den Umgang mit Boolean
 
Es erlaubt in einer if-else-Verschachtelung einen leeren begin-end-Block wegzulassen.

Chewie 16. Nov 2005 13:06

Re: Über den Umgang mit Boolean
 
Zitat:

Zitat von Robert Marquardt
Da ist noch eine Falle.
Delphi-Quellcode:
  aFehler:=Boolean(Code);
Hier verlaesst man sich darauf das Compilermagic es schon richten wird.
Besser ist
Delphi-Quellcode:
  aFehler := Code <> 0;
Das ist auch deutlicher in seiner Aussage.

Wieso Compiler-Magic?
Der Cast auf Boolean soll doch ein Cast sein, der die Daten nicht verändert, sondern nur den Typ. Das ist doch gerade der Kernpunkt des ersten Teil des Tutorials!
Würde man deine Konstruktion verwenden, bekäme man in diesem Fall keine Probleme mit einem expliziten Vergleich auf true oder false.

Robert Marquardt 16. Nov 2005 13:38

Re: Über den Umgang mit Boolean
 
Irgendwas muss der Compiler beim Cast auf Boolean machen.
Ein Boolean enthaelt nur True oder False mit Ord(True) = 1 und Ord(False) = 0.
Die Konsequenz ist das entweder fuer den Cast oder Ord Code generiert werden muss.

Khabarakh 16. Nov 2005 13:50

Re: Über den Umgang mit Boolean
 
Ich finde das Tutorial gut geschrieben, mich regt dieses "= true" auch immer auf :mrgreen: . Den leeren Block vor else habe ich aber (zum Glück) noch nie gesehen, das ist ja wirklich grausig :stupid: .
Delphi-Quellcode:
begin
  wert:=GetInt(aSatz, Fehler);
  if fehler=true then
    ShowMessage(aSatz + ': Eingabefehler!') else
  if Fehler=false then
    ShowMessage(aSatz + ': Wert: '+IntToStr(Wert)) else
    ShowMessage(aSatz + ': Hupps!');
end;
Hier finde ich die Einrückung auf den ersten Blick etwas verwirrend, besser wäre IMHO:
Delphi-Quellcode:
begin
  wert:=GetInt(aSatz, Fehler);
  if fehler=true then
    ShowMessage(aSatz + ': Eingabefehler!')
  else
    if Fehler=false then
      ShowMessage(aSatz + ': Wert: '+IntToStr(Wert))
   else
      ShowMessage(aSatz + ': Hupps!');
end;
Zitat:

SIMULA67 kennt bedingte Ausdrücke. Damit könnte man das Problem sinngemäß so lösen:
Code: markieren
Code:
IF (IF Length(string_var) >= 5 THEN False ELSE string_var[5] = 'x') THEN
    irgend_was;

Vergleichbares gibt es auch in anderen (etwas bekannteren :wink: ) Sprachen, z.B. in C# als ternären Operator:
Code:
List<string> StringList = null;
if (StringList == null ? false : StringList.Count > 0)
   Console.WriteLine(StringList[0]);
Und als Ergänzung: boolsche Kurzausdrücke in C#:
Code:
List<string> StringList = null;
// Löst eine System.NullReferenceException aus, da "&" einfach nur ein logischer Operator ist
if (StringList != null & StringList.Count > 0)
   Console.WriteLine(StringList[0]);

// Löst keine Exception aus, "&&" ist ein "logischer Bedingungsoperator" oder ""abkürzender" Operator"
// Entspricht dem Code von oben mit dem "?:" Operator
if (StringList != null && StringList.Count > 0)
   Console.WriteLine(StringList[0]);

Chewie 16. Nov 2005 14:11

Re: Über den Umgang mit Boolean
 
Zitat:

Zitat von Robert Marquardt
Irgendwas muss der Compiler beim Cast auf Boolean machen.
Ein Boolean enthaelt nur True oder False mit Ord(True) = 1 und Ord(False) = 0.
Die Konsequenz ist das entweder fuer den Cast oder Ord Code generiert werden muss.

Ich hab hier jetzt leider kein Delphi drauf, aber ich würde vermuten, dass bei folgender KOnstruktion 2 angezeigt wird:

Delphi-Quellcode:
ShowMessage(InttoStr(Ord(Boolean(2))));

Ultimator 16. Nov 2005 14:14

Re: Über den Umgang mit Boolean
 
Zitat:

Zitat von Chewie
Zitat:

Zitat von Robert Marquardt
Irgendwas muss der Compiler beim Cast auf Boolean machen.
Ein Boolean enthaelt nur True oder False mit Ord(True) = 1 und Ord(False) = 0.
Die Konsequenz ist das entweder fuer den Cast oder Ord Code generiert werden muss.

Ich hab hier jetzt leider kein Delphi drauf, aber ich würde vermuten, dass bei folgender KOnstruktion 2 angezeigt wird:

Delphi-Quellcode:
ShowMessage(InttoStr(Ord(Boolean(2))));

Jup, stimmt :)

malo 16. Nov 2005 14:16

Re: Über den Umgang mit Boolean
 
Also, ich muss ganz ehrlich sagen, dass ich gelegentlich eine Abfrage mit "= false" mache. Und zwar immer dann, wenn ich eine mehrmals verschachtelte Abfrage mach, am besten noch mit (veraschachtelten) Funktionsaufrufen. Bevor ich mich dann inmitten der Klammern und der Operatorenrangfolge verirre, oder auch nur zuviel Zeit verschwende, mich noch einen Moment damit auseinanderzusetzen, schreib ich einfach ein "= false" dahin. Das finde ich dann einfach leichter, und ich sehe auch keine besonderen Nachteile darin.

Ich persönlich finde jedenfalls, dass es übertrieben ist, sich darüber "aufzuregen", dass manche "if irgendwas = true" schreiben. Das Ganze hat auch etwas mit Programmierstil zu tun. Und wer es so übersichtlicher findet, soll es halt übersichtlicher finden. Auf die 6 Zeichen die dabei zusätzlich getippt werden (meinetwegen bei 100 maligem Aufruf 600 Zeichen) kommt es auch nicht mehr drauf an.

Bei dem Rest geb ich dir jedoch Recht.


Alles in allem ist das jedoch ein nettes Tutorial :thumb:

Tyrael Y. 16. Nov 2005 14:23

Re: Über den Umgang mit Boolean
 
Zitat:

Zitat von malo
Also, ich muss ganz ehrlich sagen, dass ich gelegentlich eine Abfrage mit "= false" mache. .....

Ich persönlich finde jedenfalls, dass es übertrieben ist, sich darüber "aufzuregen", dass manche "if irgendwas = true" schreiben. Das Ganze hat auch etwas mit Programmierstil zu tun. Und wer es so übersichtlicher findet, soll es halt übersichtlicher finden. Auf die 6 Zeichen die dabei zusätzlich getippt werden (meinetwegen bei 100 maligem Aufruf 600 Zeichen) kommt es auch nicht mehr drauf an.


Delphi-Quellcode:
if x = false then
ist ja auch richtig
besser
if not(x) then

aber

Delphi-Quellcode:
if x = True
sollte man NIEEEEEEE schreiben....
...dies kann richtig sein, aber muss nicht richtig sein

lies dir das oben bitte nochmal durch, bevor du in Zukunft Fehler im Program hast und die Quell nicht lokalisieren kannst ;)


Gruß

malo 16. Nov 2005 16:41

Re: Über den Umgang mit Boolean
 
Zitat:

Zitat von Tyrael Y.
Delphi-Quellcode:
if x = True
sollte man NIEEEEEEE schreiben....
...dies kann richtig sein, aber muss nicht richtig sein

lies dir das oben bitte nochmal durch

:wall: Jetzt hab ich auch dieses "Problem" verstanden. ;)

Jedenfalls hab ich mir das "= true" schon länger abgewöhnt. Aber das lag hauptsächlich daran, dass ich ziemlich schreibfaul bin :mrgreen:

Airblader 16. Nov 2005 16:54

Re: Über den Umgang mit Boolean
 
Hihi, also zunächst schreibe ich immer "TRUE" und "FALSE" und nicht "true" oder "True", ist für mich einfach signalgebender ;)
Allerdings schreibe ich das nie im if-Statement, um Gottes Willen. Ein Programmierer ist von Natur aus faul und abgesehen davon finde ich "Irgendwas=TRUE" stilistisch einfach schrecklich - so sieht Code doch nicht schön aus ;)

air

Brüggendiek 16. Nov 2005 18:06

Re: Über den Umgang mit Boolean
 
Hallo!

Da war mir in meinem Tut doch tatsächlich der falsche Code reingerutscht - habe ich oben verbessert und markiert :oops: .

Sind ja in kurzer Zeit viele Reaktionen gekommen. Antworten darauf kann ich leider heute nicht mehr schreiben. Zum Einen habe ich im Moment viel zu tun und morgen ist hier in Dortmund Roadshow - da bin ich angemeldet.

Gruß

Dietmar Brüggendiek

Oxmyx 16. Nov 2005 18:19

Re: Über den Umgang mit Boolean
 
Zitat:

Zitat von Airblader
Hihi, also zunächst schreibe ich immer "TRUE" und "FALSE" und nicht "true" oder "True", ist für mich einfach signalgebender ;)
Allerdings schreibe ich das nie im if-Statement, um Gottes Willen. Ein Programmierer ist von Natur aus faul und abgesehen davon finde ich "Irgendwas=TRUE" stilistisch einfach schrecklich - so sieht Code doch nicht schön aus ;)

air

Naja, ein mit C vertrauter Programmierer würde vielleicht meinen, dass du mit TRUE und FALSE die Windows-Konstanten meinst, die als Integer mit 4 Bytes definiert sind.

Zum Tutorial muss ich sagen, dass ich den Schreibstil etwas daneben finde. Es wird dem Leser ständig suggeriert, dass er schwer von Begriff sei.

negaH 17. Nov 2005 06:34

Re: Über den Umgang mit Boolean
 
Zitat:

Der Cast auf Boolean soll doch ein Cast sein, der die Daten nicht verändert, sondern nur den Typ.
Das ist doch gerade der Kernpunkt des ersten Teil des Tutorials!

Würde man deine Konstruktion verwenden, bekäme man in diesem Fall keine Probleme mit einem expliziten Vergleich auf true oder false.

if Boolean = True then
sollte man NIEEEEEEE schreiben....
...dies kann richtig sein, aber muss nicht richtig sein
Ich weis nicht, dein "Tutorial" zieht meiner Meinung nach die falschen Schlußfolgerungen.

Delphi-Quellcode:

if Boolean = True then
Ist zwar eine umständliche Boolsche Auswertung aber immer noch eine korrekte und PASCAL konforme Auswertung die immer richtig umgesetzt wird. Es ist egal ob man dabei den Typen Booelan, WordBool, Bool, ByteBool oder LongBool benutzt.

Das eingentliche Problem mit falschen Auswertung solcher Konstrukte liegt im CAST eines beliebigen Wertes in einen Boolean Datentyp. Robert hat also oben schon absolut die saubere Lösung zur Vermeidung solcher CASTs aufgezeigt.

Denn das nun

Delphi-Quellcode:
if Boolean then
// oder
if not Boolean then
mit casted Datentypen denoch korrekt funktioniert liegt ausschließlich nur an der Art & Weise wie der Compiler diese Abfragen in Maschinencode umsetzt. In diesem speziellen Falle erzeugt nämlich der Compiler keinen direkten Vergleich zweier Datenwerte zueinander sondern benutzt spezielle Features der CPU die immer quasi ein Auschlußverfahren anwenden. Auf Grund dessen ist FALSE als 0 definiert und der Compiler erzeugt einen Code der <> 0 oder == 0 testet, je nach TRUE oder FALSE Bedingung.

Das der Compiler dies so macht ist keine zwangsläufige und dokumentierte Grundlage zur Auswertung Boolscher Bedingungen. Dieses Verhalten ist undokumentiert und man kann sich darauf nicht verlassen !
Der Compiler könnte also interen selber ebenfalls einen direkten Wertvergleich durchführen, dh. also aus

Delphi-Quellcode:
if Boolean then
// macht der Compiler einen Maschinencode wie
if Boolean = Truee then
und würde dann ebenfalls auf die Schnauze fallen mit casted Boolean's.

Die eigentliche Ursache des Problems liegt also nicht in der Art & Weise der Abfrage eines Booleans sondern in der Erzeugung eines Booleans per TypCasts !!

Ergo: Sich hinzustellen und zu behaupten das eine PASCAL konforme Abfrage schlecht wäre und zu Fehlern führt ist die falsche Konsequenz. Dies stimmt nicht, da die Ursache einzigst im Cast eines Datentypes liegt. Man kann zwar versuchen den Schimmelbefall eines Hauses durch einen sauberen Anstrich zu verdecken, aber nur die Beseitigung des Übels schafft wirklich abhilfe. Das macht aber einen schlechteren Hausanstrich nicht verantwortlich dafür das der Schimmelbefall immer noch da ist.

Das die umständliche Abfrage eines Boolschen Datentypes per zusätzlichem Boolschen Vergleich doppelt gemoppelt ist und somit sehr un-clever ist sei unbestritten, aber nicht falsch im Sinne der PASCAL Semantik.

Schaut mal den IT Professoren auf Bayern3 im <IT> Grundkurs zu und was die für schreckliche PASCAL Sourcen als Lehrmittel heranziehen. Da habe ich solche doppeltgemoppelten Boolschen Abfragen schon sehr oft gesehen.

Gruß Hagen

[edit]
Die Frage eines Stils des "Bullet proof" Programmieren kann man aber mit deinem Tutorial sehr wohl begründen. Es ist also sauberer Boolsche Datentypen direkt Boolsch auszuwerten und macht auf Grund der speziellen Auswertung solcher Abfragen durch den Compiler den Code sicherer. Aber er wird dadurch nicht richtiger als die un-celvere Art der Boolschen Abfragen !
[/edit]

Merlin2001 25. Jul 2006 09:44

Re: Über den Umgang mit Boolean
 
Hallo Dietmar,

ich bin Delphi-Anfänger und verstehe folgendes nicht:

Zitat:

Zitat von Brüggendiek
Auswertung boolscher Ausdrücke

(...)
Die verkürzte Auswertung von Boolean-Ausdrücken führt aber zu einer weiteren bösen Falle:
Delphi-Quellcode:
if (Length(StringVar)>=5) and (StringVar[5]='x') then
  IrgendWas;
ist eine ganz gefährliche Sache. Bei optimiertem Boolean wird der 2. Teil nicht mehr ausgewertet; ohne Optimierung jedoch ergibt sich bei AnsiString die Situation, daß der Index außerhalb des Wertebereichs liegen kann.
Solange man in seiner Unit/Komponente den B-Compilerschalter richtig einstellt, sollte beim Austausch von Quellcode nichts passieren. Wenn man sich jedoch auf die Einstellung des Compilers verläßt, ist man verlassen und erhält dann vom Anwender Rückmeldungen, daß das Ganze "manchmal" fehlerhaft läuft.

Du sprichst ja davon, dass bei manchen Abfragen das Ergebnis frühzeitig feststeht.
Wenn ich aber

Delphi-Quellcode:
if (Length(StringVar)>=5) and (StringVar[5]='x') then
  IrgendWas;
schreibe, dann müssen doch auf jeden Fall beide Bedingungen geprüft werden, oder? Schließlich lässt sich aus der Richtigkeit der ersten Bedingung nicht auch das Zutreffen der zweiten schließen (jedenfalls in meiner Logik ^^).
Bitte sei so nett und erklär es mir noch mal etwas genauer ;)

Gruß
Marcus

Flocke 25. Jul 2006 09:54

Re: Über den Umgang mit Boolean
 
Zitat:

Zitat von Merlin2001
Wenn ich aber

Delphi-Quellcode:
if (Length(StringVar)>=5) and (StringVar[5]='x') then
  IrgendWas;
schreibe, dann müssen doch auf jeden Fall beide Bedingungen geprüft werden, oder? Schließlich lässt sich aus der Richtigkeit der ersten Bedingung nicht auch das Zutreffen der zweiten schließen (jedenfalls in meiner Logik ^^).

Wenn die erste Bedingung schon falsch ist (die Länge des Strings also kleiner als 5), dann kann der gesamte Ausdruck nicht mehr wahr werden. Nur dann wird die weitere Auswertung abgebrochen. Das liegt daran, dass "False AND Irgendwas" immer "False" liefert, genau wie "True OR Irgendwas" immer "True".

stefangeorg 25. Jul 2006 10:02

Re: Über den Umgang mit Boolean
 
Servus,

Zitat:

Da hilft
Delphi-Quellcode:
BoolVar:=not (IntVar=5);

Hier würde ich schreiben:
Delphi-Quellcode:
BoolVar:=IntVar<>5;
Was ist denn hier schneller / angebrachter / richtiger?

Grüße,

Georg

RavenIV 25. Jul 2006 10:26

Re: Über den Umgang mit Boolean
 
würdest Du bitte aus dem "Tutorial" ein pdf erstellen, in dem alle Anmerkungen / Korrekturen aus diesem Thread eingeflossen sind?

Danke im Voraus.

negaH 26. Sep 2006 16:09

Re: Über den Umgang mit Boolean
 
Zitat:

Was ist denn hier schneller / angebrachter / richtiger?
Keines von beiden ist richtiger noch schneller als das andere, aber lesbarer und kürzer und nicht so umständlich ist

Delphi-Quellcode:
BoolVar := Value <> 5;
sehe ich sowas
Delphi-Quellcode:
BoolVar := not (Value = 5);
in einem Source so weis ich sofort mit Sicherheit das der Programmierer der dies so schreibt eben nicht in der Lage ist Formeln umzustellen. Und das Ziel ist es eben auch ein Problem im Source so zu lösen das es fast schon genial einfach erscheint.

Gruß Hagen

TiGü 7. Feb 2012 09:28

AW: Über den Umgang mit Boolean
 
Wie sieht denn das eigentlich im Verhältnis zu C/C++ aus?
Oft sehe ich bei Kollegen die in diesen Sprachen programmieren Sachen wie ... == false/true!

Sherlock 7. Feb 2012 09:38

AW: Über den Umgang mit Boolean
 
Bei C/C++ ist eh Hopfen und Malz verloren.
*SCNR*

Spaß beiseite: Es kann bei den von Dir genannten Fällen durchaus sein, daß die zu vergleichende Variable gar keine Boolean ist, sondern zB ein Integer oder auch ganz was anderes, C erlaubt entsprechend phantasievolle Vergleiche, und gibt sogar manchmal die erwarteten Ergebnisse zurück. Da lob ich mir doch eine typensichere Sprache.

Sherlock

Medium 7. Feb 2012 09:44

AW: Über den Umgang mit Boolean
 
Geade bei C (ohne ++) gab es das Problem, dass es keine standardmäßigen Konstanten für true/false gab, und somit jeder in seinem Abschnitt seine eigenen derlariert hat. Dadurch konnte er dann recht sicher sein, dass Gleichheit besteht, komfortabel war/ist das insgesamt aber wohl eher nicht :)

Bei C(++) gilt: 0=false, egal was für einen Typ man vor sich hat. So wird ein "if Assigned(MyInstance) then..." dort oft auch zu einem "if (MyInstance) {...}".

himitsu 7. Feb 2012 10:02

AW: Über den Umgang mit Boolean
 
Joar, False ist eigenttlich immer 0 (wenn der Boolean als ordinaler Type angelegt ist), also "nichts".

Wobei aber das Delphi-True = 1
und das C-True = -1
Code:
Die standardisierten Konstanten:

True:
  Boolean        = $01
  ByteBool / bool = $FF
  WordBool       = $FFFF
  LongBool / BOOL = $FFFFFFFF

False:
  Boolean        = $00
  ByteBool / bool = $00
  WordBool       = $0000
  LongBool / BOOL = $00000000
In der Auswertung ist es aber immer:
False = 0
True <> 0
True = nicht False

Und schon fällt auf, warum
Delphi-Quellcode:
= True
nicht korrekt sein kann.
Delphi-Quellcode:
= False
würde zwar problemlos gehn, aber wenn man
Delphi-Quellcode:
= True
nicht nehmen darf kann, warum soll man sich dann mit
Delphi-Quellcode:
= False
auch noch rumschlagen. (schön einheitlich halt)

JamesTKirk 7. Feb 2012 10:42

AW: Über den Umgang mit Boolean
 
Zitat:

Zitat von himitsu (Beitrag 1149609)
Joar, False ist eigenttlich immer 0 (wenn der Boolean als ordinaler Type angelegt ist), also "nichts".

Wobei aber das Delphi-True = 1
und das C-True = -1
Code:
Die standardisierten Konstanten:

True:
  Boolean        = $01
  ByteBool / bool = $FF
  WordBool       = $FFFF
  LongBool / BOOL = $FFFFFFFF

False:
  Boolean        = $00
  ByteBool / bool = $00
  WordBool       = $0000
  LongBool / BOOL = $00000000

Bei Free Pascal kommen dann noch QWordBool, Boolean16, Boolean32 und Boolean64 (letztere drei seit 2.6.0) hinzu :mrgreen:

Code:
True:
  QWordBool      = $FFFFFFFFFFFFFFFF
  Boolean16       = $0001
  Boolean32       = $00000001
  Boolean64       = $0000000000000001 

False:
  QWordBool      = $0000000000000000
  Boolean16       = $0000
  Boolean32       = $00000000
  Boolean64       = $0000000000000000
Gruß,
Sven

Medium 7. Feb 2012 11:06

AW: Über den Umgang mit Boolean
 
Letztlich ist wohl auch unter C(++) der direkte Vergleich genau so kritisch wie in Delphi. Vor allen Dingen kann bei einem nackten "if mybool then" ein schlankes "jz" bzw. "jnz" erzeugt werden, ohne vorher noch ein "cmp" zu machen, sowie den Vergleichswert zu laden oder verpointern.
Und da eben letztlich immer ein jz oder jnz mitspielt, ist ein "if 0" immer der richtige weg, und ein "if not 0" die logische Konsequenz. Dabei tritt dann nur eben das Problem auf, dass Datentypen breiter als 1 Bit sind, und sich somit je nach Architektur beliebig viele "nicht nulls" bilden ließen. Auch in C-likes, und daher ist auch da zumindest ein "== true" eher smelly.
Interessant finde ich, dass man für beide o.g. True-Konstrukte ($FFFFFFFF und 1) logisch und semantisch sinnvoll argumentieren kann, wobei beides bei vernünftiger Verwendung (kein Vergleich machen) auch problemlos gemischt benutzt werden kann. Delphi geht den "mathematischen" Weg 0-1, C den technischen, bei dem einfach das "not" als logischer Operator auf den gesamten Operanden angewendet wird.


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:28 Uhr.

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