und die Funktion "BerechneA()" liefert false zurück, dann steht jetzt
schon fest, dass das Ergebnis false sein wird und daher wird meines
Wissens die Funktion "BerechneB()" gar nicht mehr aufgerufen.
Frage:
Ist dieses Verhalten Compiler-spezifisch oder ist es in C/C++ so
festgelegt?
Und wie nennt man das im Fachjargon?
Danke!
Bronco schrieb:> Ist dieses Verhalten Compiler-spezifisch oder ist es in C/C++ so> festgelegt?
Das ist in C so festgelegt:
> Unlike the bitwise binary & operator, the && operator guarantees left-> to-right evaluation; if the second operand is evaluated, there is a> sequence point between the evaluations of the first and second operands.> If the first operand compares equal to 0, the second operand is not> evaluated.http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
Kapitel 6.5.13
Bronco schrieb:> bool ergebnis = BerechneA() && BerechneB();
Dieses "Zeilensparen" stammt noch aus der Zeit, als man jede Zeile
einzeln in eine Lochkarte stanzen musste.
Heute gibt dir keiner Geld dafür, daß du den gleichen Code in 2 zeilen
weniger packen kannst.
Also machs sauber nacheinander.
Nennt sich z.B "short cicuit"
Und ist im C-und C++-Standard so festgelegt.
Für den logical and operator liest sich das z.B so:
>Unlike &, && guarantees left-to-right>evaluation: the second operand is not evaluated if the first operand is false.
Oliver
Dussel schrieb:> Hier scheint es wohl um C zu gehen, oder? In Java gibt es für genau> diesen Fall spezielle Operatoren
Nämlich &&, genauso wie in C, oder nicht?
Udo Schmitt schrieb:> Bronco schrieb:>> bool ergebnis = BerechneA() && BerechneB();>> Dieses "Zeilensparen" stammt noch aus der Zeit, als man jede Zeile> einzeln in eine Lochkarte stanzen musste.> Heute gibt dir keiner Geld dafür, daß du den gleichen Code in 2 zeilen> weniger packen kannst.> Also machs sauber nacheinander.
"Sauber nacheinander" heißt dann aber u.U. auch "schön langsam". Der
"Kurzschluß" ist ein durchaus erwünschtes Programmierkonstrukt:
printf("zweimillionste Stelle von pi = %d\n",stelle);
Hat eher mit Zyklen- als mit Zeilensparen zu tun. Hier würd' ich lieber
nicht "alles sauber nacheinander" machen wollen ;).
Aufpassen muß man natürlich darauf, daß der zweite Aufruf nach dem '&&'
nirgendwo irgendwelche Seiteneffekte hat, von denen der weiteren
Programmablauf abhängt.
Udo Schmitt schrieb:> Heute gibt dir keiner Geld dafür, daß du den gleichen Code in 2 zeilen> weniger packen kannst.> Also machs sauber nacheinander.
Also in 3 Zeilen:
bool ergebnis = BerechneA();
if(ergebnis)
ergebnis = BerechneB();
oder
bool ergebnis = false;
ergebnis = BerechneA();
if(ergebnis) ergebnis = BerechneB();
Beide Varianten sind meiner Meinung nach deutlich schlechter lesbar als
bool ergebnis = BerechneA() && BerechneB();
A. K. schrieb:> Das soll im "GCC" Forum gelegentlich vorkommen.
Ja, aber im Home-Bereich ist das nicht so ersichtlich ;-)
Ich bin direkt von der Startseite zu dem Beitrag gekommen. Erst nach dem
Absenden habe ich gesehen, welches Forum das ist.
Yalu X. schrieb:> Dussel schrieb:>> Hier scheint es wohl um C zu gehen, oder? In Java gibt es für genau>> diesen Fall spezielle Operatoren>> Nämlich &&, genauso wie in C, oder nicht?
Da wird nur solange ausgewertet, bis der Ausdruck sicher bestimmt ist.
Ein einfaches & oder | im Ausdruck wertet immer beide Ausdrücke aus.
http://openbook.galileocomputing.de/javainsel/javainsel_02_004.html#dodtp44c70ec5-17d6-4493-bac6-218399d01cf8
Dussel schrieb:> Ein einfaches & oder | im Ausdruck wertet immer beide Ausdrücke aus.
Ja, die bitweisen Operatoren, werten immer beide Operanden aus, weil es
streng genommen keine logischen, sondern Rechenoperatoren (wie + und -)
sind, auf die die Kurzschlussauswertung für die meisten Werte nicht
anwendbar ist.
Das ist in C aber exakt gleich.
thestrangler schrieb:> Beide Varianten sind meiner Meinung nach deutlich schlechter lesbar als> bool ergebnis = BerechneA() && BerechneB();
Einen Punkt hat der Udo schon.
Bei
thestrangler schrieb:> bool ergebnis = false;> ergebnis = BerechneA();> if(ergebnis) ergebnis = BerechneB();>> Beide Varianten sind meiner Meinung nach deutlich schlechter lesbar als>> bool ergebnis = BerechneA() && BerechneB();
Sind schlechter lesbar, dafür aber richtig.
Es geht doch darum, daß berechneB() unbedingt ausgeführt werden muss,
weil nämlich berechneB() irgendein (globalen) Wert berechnet, der später
gebraucht wird. (So zumindest war mein Verständnis der Anfangsfrage.)
Und genau das ist so in dem Einzeiler nicht erkennbar und somit für
jemand anderen, der den Code nicht selbst geschrieben hat nicht ohne
weiteres zu erkennen.
Wenn also BerechneA() und BerechneB() auf jeden Fall ausgeführt werden
müssen, weil sie eben noch mehr machen als nur das boolsche Ergebnis für
den Vergleich zurückzuliefern, dann sollte das auch im Programm deutlich
werden und eher so aussehen:
bool ergebnisA = berechneA();
bool ergebnisB = berechneB();
if (ergebnisA && ergebnisB) ...
Zumindest so hatte ich die Anfangsfrage verstanden, daß nämlich der
Abbruch einer boolschen Auswertung zu Problemen führt weil dann
berechneB() nicht mehr ausgeführt wird.
Wenn ich das missverstanden haben sollte, dann habt ihr recht, ein
bool ergebnis = BerechneA() && BerechneB();
ist völlig ok und übersichtlich.
Udo Schmitt schrieb:> Zumindest so hatte ich die Anfangsfrage verstanden, daß nämlich der> Abbruch einer boolschen Auswertung zu Problemen führt weil dann> berechneB() nicht mehr ausgeführt wird.
Ich glaube, das hast du nur in die Frage hineininterpretiert.
Wer Funktionen mit derartigen Seiteneffekten zimmert und dann in
einer Kurzschlussoperation benutzt, hat aber sowieso ein ganz anderes
Problem.
Udo Schmitt schrieb:> Zumindest so hatte ich die Anfangsfrage verstanden, daß nämlich der> Abbruch einer boolschen Auswertung zu Problemen führt weil dann> berechneB() nicht mehr ausgeführt wird.
Ich glaube, er meinte genau das Gegenteil.
Bronco schrieb:> Ist dieses Verhalten Compiler-spezifisch oder ist es in C/C++ so
Das habe ich so interpretiert, dass er die Kurzschlussauswertung gerne
nutzen möchte, er sich aber nicht sicher war, ob sie wirklich auch in
jedem C-Compiler implementiert ist.
Bronco schrieb:> wird wahrscheinlich nicht jedem sofort klar, dass der SuperGAU nur dann> verhindert wird, wenn irgendetwas unwichtiges true ist.
Tja, es ist so wie es ist: man sollte die Grundregeln der Sprache halt
kennen.
Vermuten reicht nicht.
Oliver
Yalu X. schrieb:> Ja, die bitweisen Operatoren, werten immer beide Operanden aus, weil es> streng genommen keine logischen, sondern Rechenoperatoren (wie + und -)> sind, auf die die Kurzschlussauswertung für die meisten Werte nicht> anwendbar ist.
Ich weiß nicht, ob das in Java auch so ist. In dem verlinkten Buch steht
es als neue Operatoren. Und da in Java Wahrheitswerte keine Zahlen sind,
denke ich, dass das in Java durchaus neue logische Operatoren sein
können.
Dussel schrieb:> Ich weiß nicht, ob das in Java auch so ist. In dem verlinkten Buch steht> es als neue Operatoren. Und da in Java Wahrheitswerte keine Zahlen sind,> denke ich, dass das in Java durchaus neue logische Operatoren sein> können.
Du hast recht, ich aber auch :)
Hab's gerade ausprobiert: In Java scheint der &-Operator polymorph zu
sein. Es gibt ihn sowohl für int- als auch für boolean-Operanden. Im
ersten Fall werden die beiden Operanden wie in C bitweise und-verknüpft,
im zweiten liefern die bitweise und die logische Und-Verknüpfung sowieso
dasselbe Ergebnis, da die boolean-Werte de facto nur ein (relevantes)
Bit enthalten.
Der Compiler stellt dabei sicher, dass, wenn einer der beiden Opernden
boolean ist, dies auch für den anderen gilt. Somit kann man den
&-Operator tatsächlich problemlos auch für logisches Und verwenden.
In C hingegen werden boolean-Werte vor der eigentlichen Verknüpfung nach
int konvertiert, was die Verwendung von & als Logikoperation etwas
problemantisch macht, denn
2 && 1 (logisches Und) ergibt wie erwartet 1 (true),
true & true ebenfalls,
aber
2 & true (entspricht 2 & 1) ergibt 0 (false)
Dieser dritte Fall führt in Java zu einer Fehlermeldung.
@ Bronco (Gast)
>bool ergebnis = IrgendetwasUnwichtiges() && SuperGAUVerhindern();>wird wahrscheinlich nicht jedem sofort klar, dass der SuperGAU nur dann>verhindert wird, wenn irgendetwas unwichtiges true ist.
Das ist so oder so ein Programmierfehler! Denn so eine
SuperGAUverhinderungsfunktion hat in dieser Konstruktion SO oder SO
NICHTS zu suchen! Das ist einer der "netten" Seiteneffekte von C, die
man tunlichst NICHT nutzen sollte. Eigentlich sollten solche Funktionen
MIT Seiteneffekten (Schreibzugriff auf globale Daten, IOs etc.) NIE in
logischen Ausdrücken auftauchen! Dort dürfen nur rein passive Funktionen
stehen! (Wenn man es sauber machen will)
Ich verwende gerne Konstrukte wie:
if (foo && foo->bar && foo->bar->foobar) {
...
}
um auf verschachtelte Pointer-Strukturen zuzugreifen, wenn nicht
sichergestellt ist, dass auch alle Pointer auf etwas sinnvolles zeigen.
Da ist dann das Short-Cirucuit Verhalten äußerst hilfreich und man
vermeidet mehrfach verschachtelte if-Konstrukte.
Yalu X. schrieb:>> Zumindest so hatte ich die Anfangsfrage verstanden, daß nämlich der>> Abbruch einer boolschen Auswertung zu Problemen führt weil dann>> berechneB() nicht mehr ausgeführt wird.>> Ich glaube, er meinte genau das Gegenteil.
Ich kann's Euch sagen ;-)
Ich benutze Kurzschlussauswertung (auch wenn ich ihren Namen nicht
kannte) bewußt in Konstrukten wie
1
if((pointer)!=0&&(pointer->Funktion()==OKAY))
Jetzt hab ich folgendes gebaut:
1
boolsuccess=true;// Soll anzeigen, ob es 10x geklappt hat
2
for(i=0;i<10;i++)
3
{
4
success&=Bitte10xAufrufen();
5
}
Das funktioniert, weil "&=" bitweise verknüpft und keine
Kurzschlussauswertung stattfindet.
Dann dachte ich mir: "100% korrekt ist das aber nicht, bool und bitweise
zu vermischen" und hab folgendes draus gemacht:
1
boolsuccess=true;// Soll anzeigen, ob es 10x geklappt hat
2
for(i=0;i<10;i++)
3
{
4
success=success&&Bitte10xAufrufen();
5
}
Und da bin ich prompt auf die Nase geflogen: Sobald success einmal false
ist, wird Bitte10xAufrufen() nicht mehr aufgerufen.
Wenn man in den Assembler-Code schaut, ist es auch absolut logisch:
Bitweise AND (&) und OR (|) ergibt echte Rechenbefehl der ALU.
Bootlsches AND (&&) und OR (||) ergibt Programmfluss (Call, Compare,
Jump), und damit wird die Auswertung des zweiten Operanten ggf. einfach
übersprungen.
Bronco schrieb:> Jetzt hab ich folgendes gebaut:> bool success = true; // Soll anzeigen, ob> es 10x geklappt hat> for (i = 0; i < 10; i++)> {> success &= Bitte10xAufrufen();> }
Es ist halt wichtig, dass Bitte10xAufrufen() für "true" eine 1 und nicht
irgendeine andere von 0 verschiedene Zahl zurückgibt. Idealerweise ist
Bitte10xAufrufen() vom Typ bool, dann bist du auf der sicheren Seite.
> success = success && Bitte10xAufrufen();
Es funktioniert auch mit &&, wenn du die Operanden vertauschst:
Yalu X. schrieb:> Es funktioniert auch mit &&, wenn du die Operanden vertauschst:> success = Bitte10xAufrufen() && success;
Ist aber meiner Meinung nach gaz schlechter Stil. Was passiert wenn ein
Kollege zwei Jahre später in dem Ausdruck was ändert oder erweitert. Da
wird ganz schnell ein Fahler eingebaut.
Dann lieber wie ich es oben besagt habe oder wie Hans es auch gesagt
hat.
Der wichtigste (und meiner Meinung nach auch völlig ok) Verwendungsfall
ist der einen pointer oder Objekt auf null zu prüfen ehe man ihn
referenziert/benutzt.
Falk Brunner schrieb:> Eigentlich sollten solche Funktionen> MIT Seiteneffekten (Schreibzugriff auf globale Daten, IOs etc.) NIE in> logischen Ausdrücken auftauchen! Dort dürfen nur rein passive Funktionen> stehen! (Wenn man es sauber machen will)
Sehe ich ganz genauso. Siehe Beitrag oben.
Bronco schrieb:> success &= Bitte10xAufrufen();Bronco schrieb:> success = success && Bitte10xAufrufen();
Die beiden Zeilen machen aber nicht das selbe, nicht mal das gleiche...
&= ist nicht ... = ... && ...
Oliver
Ich hatte das Gefühl, dass es dem TO darum ging, dass die zweite
Funktion erst gar nicht aufgerufen wird. Wenn die erste Funktion false
liefert.
Ich würde es mit:
bool ergebnis = BerechneA();
ergebnis = BerechneB() && ergebnis;
versuchen.
Irgendwo in den tiefen von C gibt es doch noch die Grundregel:
"Es geht von links nach rechts", wenn irgendeine Hierarchie nicht was
Anderes sagt.
@ Bronco (Gast)
>bool success = true; // Soll anzeigen, ob es 10x geklappt hat>for (i = 0; i < 10; i++)>{> success &= Bitte10xAufrufen();>}>Das funktioniert, weil "&=" bitweise verknüpft und keine>Kurzschlussauswertung stattfindet.
Nein, das hat damit nix zu tun.
>Dann dachte ich mir: "100% korrekt ist das aber nicht, bool und bitweise>zu vermischen"
Ist es auch nicht.
> und hab folgendes draus gemacht:>bool success = true; // Soll anzeigen, ob es 10x geklappt hat>for (i = 0; i < 10; i++)>{> success = success && Bitte10xAufrufen();>}>Und da bin ich prompt auf die Nase geflogen: Sobald success einmal false>ist, wird Bitte10xAufrufen() nicht mehr aufgerufen.
Falsch. Deine Logik ist fehlerhaft. Die Logik des Programms STIMMT! Auch
mit Kurzschlußauswertung. Denn sobald EINMAL success == FALSE ist, kann
es niemals 10x TRUE sein.
Amateur schrieb:> Irgendwo in den tiefen von C gibt es doch noch die Grundregel:> "Es geht von links nach rechts", wenn irgendeine Hierarchie nicht was> Anderes sagt.
Vorsicht. Das ist eine grobe Verallgemeinerung, die so nicht gilt.
In
1
c=a()+b();
hast du keineswegs die Gewähr, dass a() vor b() aufgerufen wird. Das das
bei
1
c=a()&&b();
so ist, liegt daran, dass && einen Sequence Point impliziert.
D.h. wenn du schon eine Grundregel haben willst, dann halte dich lieber
an: die Reihenfolge der Auswertungen ist undefiniert, es sei denn es
handelt sich um einen Sonderfall, für den explizit feststeht, wie die
Reihenfolge sein muss.
Wichtig, denn das verwechseln viele. Operator Precedence bzw.
Rechts/Links Assoziation definiert nicht die Auswertereihenfolge! Diese
Dinge regeln zb, wie die Einzelergebnisse von zb
1
d=a()+b()*c();
miteinander verrechnet werden müssen. Sie legen aber nicht fest, in
welcher Reihenfolge die Einzelergebnisse erzielt werden!