Von links nach Rechts. Das hat auch nichts mit dem GCC zu tun, das ist
im C-Standard festgelegt. Stichwort shortcut-evaluation.
Wenn foo1 false ist wird der Rest nicht mehr aufgerufen, wenn dann foo2
false ist wird abgebroche u.s.w. das heißt foo4 wird nur aufgerufen wenn
foo1, foo2 und foo3 true ergeben.
Tja, ist nur blöd, wenn in Foo2-4() auch noch etwas aufgerufen wird, was
erledigt werden soll.
Dann lieber
ret1=Foo1();
ret2=Foo2();
ret3=Foo3();
ret4=Foo4();
if (ret1 && ret2 && ret3 && ret4) ...
Pete K. schrieb:> Tja, ist nur blöd, wenn in Foo2-4() auch noch etwas aufgerufen> wird, was> erledigt werden soll.
Da ist dann nicht blöd, sondern schlicht ein Programmierfehler.
Oliver
Dr. Sommer schrieb:> So werden immer alle aufgerufen.
Aber nicht korrekt ausgewertet. Wenn Foo1() eine 1 zurückgibt,
Foo2() eine 2, Foo3() eine 4 und Foo4() eine 8, dann ist das
Ergebnis des bitweisen UND eine 0, obwohl das Boolesche UND ein
True gegeben hätte.
Jörg W. schrieb:> Aber nicht korrekt ausgewertet. Wenn Foo1() eine 1 zurückgibt,> Foo2() eine 2, Foo3() eine 4 und Foo4() eine 8
Ja stimmt, ich war jetzt von C++ - "bool" Rückgabetypen ausgegangen, da
gibts nur "true" und "false".
Dr. Sommer schrieb:> Ja stimmt, ich war jetzt von C++ - "bool" Rückgabetypen ausgegangen, da> gibts nur "true" und "false".
Gibt's bei C auch, aber ohne die Deklaration der Funktionen zu
sehen, kann man nicht sagen, was es genau ist.
Mit && ist es egal.
Quellkothistamin schrieb:> return (ret1 && ret2 && ret3 && ret4);
Und die Klammern sind auch nicht nötig.
Jörg W. schrieb:> Gibt's bei C auch, aber ohne die Deklaration der Funktionen zu> sehen, kann man nicht sagen, was es genau ist.
Und dem kann man nicht versehentlich auch eine Zahl außer 0 oder 1
zuweisen?
Jörg W. schrieb:> Mit && ist es egal.
Aber das hat ja ggf. nicht die gewünschte Funktion...
Dr. Sommer schrieb:>> Gibt's bei C auch, aber ohne die Deklaration der Funktionen zu>> sehen, kann man nicht sagen, was es genau ist.> Und dem kann man nicht versehentlich auch eine Zahl außer 0 oder 1> zuweisen?
Kann man, wird aber auf [false, true] abgebildet:
1
#include<stdbool.h>
2
3
boolgetresult(inti)
4
{
5
if(i<0)return-1;
6
if(i>0)returntrue;
7
returnfalse;
8
}
Compiliert zwar ohne Warnung, gibt aber:
1
.file "foo.c"
2
__SP_H__ = 0x3e
3
__SP_L__ = 0x3d
4
__SREG__ = 0x3f
5
__tmp_reg__ = 0
6
__zero_reg__ = 1
7
.text
8
.global getresult
9
.type getresult, @function
10
getresult:
11
/* prologue: function */
12
/* frame size = 0 */
13
/* stack size = 0 */
14
.L__stack_usage = 0
15
ldi r18,lo8(1)
16
or r24,r25
17
brne .L2
18
ldi r18,0
19
.L2:
20
mov r24,r18
21
ret
22
.size getresult, .-getresult
23
.ident "GCC: (GNU) 4.7.2"
Mal für den AVR compiliert, da ist es einfacher überschaubar, dass
wirklich nur 0 oder 1 als Ergebnis zurückgeliefert werden. Für
amd64 compiliert ergibt sich:
1
.file "foo.c"
2
.text
3
.globl getresult
4
.type getresult, @function
5
getresult:
6
.LFB0:
7
.cfi_startproc
8
testl %edi, %edi
9
setne %al
10
ret
11
.cfi_endproc
12
.LFE0:
13
.size getresult, .-getresult
14
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4"
15
.section .note.GNU-stack,"",@progbits
Da hätte ich jetzt nachsehen müssen, was SETNE genau tut. ;-) Aber
es ist auch hier eigentlich offensichtlich, dass es keine dreifache
Fallunterscheidung gibt, wie sie im Quellcode drin steht.
Jörg W. schrieb:> Dr. Sommer schrieb:>> Ja stimmt, ich war jetzt von C++ - "bool" Rückgabetypen ausgegangen, da>> gibts nur "true" und "false".>> Gibt's bei C auch, aber ohne die Deklaration der Funktionen zu> sehen, kann man nicht sagen, was es genau ist.>> Mit && ist es egal.
Man kann es auch in C passend schreiben:
1
if(f1()!=0&f2()!=0&f3()!=0&f4()!=0)...
Damit hat man short circuit ausgehebelt, egal welchen genauen Wert die
Funktionen liefern.
Falls man es braucht...
Quellkothistamin schrieb:> bei solchen IFs rollt es mir immer die Zehennägel auf.
Warum? Short cut evaluation ist - wenn man es richtig anzuwenden weiß -
einfach nur praktisch.
Frank M. schrieb:> Short cut evaluation ist - wenn man es richtig anzuwenden weiß - einfach> nur praktisch.
Ich erinnere mich noch an Pascal, bei dem man immer schreiben musste:
1
if someptr <> nil then begin
2
if @someptr = 42 then …
3
end
weil es ebne keine definierte short cut evaluation gab, die garantiert
hätte, dass
Frank M. schrieb:> short cut evaluation ist - wenn man es richtig anzuwenden weiß -> einfach nur praktisch.
Wenn man Seiteneffekte in foo1(),...,foo4() hat (wenn es keine gibt, ist
die Reihenfolge egal) und die short circuit evaluation implizit zur
Ablaufsteuerung des Programms nutzt, verdient das sanfte Ohrfeigen wegen
Cleverness.
Das Konstrukt müsste man dokumentieren. Oder, was einfacher wäre, den
Code so schreiben, dass man sofort sieht, was unter welchen Bedingungen
ausgeführt wird und dass das auch so gemeint ist.
Tom schrieb:> Das Konstrukt müsste man dokumentieren. Oder, was einfacher wäre, den> Code so schreiben, dass man sofort sieht, was unter welchen Bedingungen> ausgeführt wird und dass das auch so gemeint ist.
Short circuit evaluation gehört zur Sprache C. Entweder versteht man sie
oder man versteht sie nicht.
Trotzdem sollte man C-Code immer verständlich schreiben, klar. Aber wenn
ich schreibe:
1
if(foo1()&&
2
foo2()&&
3
foo3()&&
4
foo4())
5
{
6
...
7
}
dann erwarte ich, dass der Leser dieses versteht als kürzere
Schreibweise von:
1
if(foo1())
2
{
3
if(foo2())
4
{
5
if(foo3())
6
{
7
if(foo4())
8
{
9
...
10
}
11
}
12
}
13
}
Wenn nicht, kann er kein C.
P.S.
Ich erweitere meine obige Aussage:
Short circuit evaluation ist nicht nur praktisch, sondern auch besser
lesbar.
ist durch Eleganz und Aussagekraft kaum zu überbieten. Hier werden die
Aufrufe von fooX() abgebrochen, sobald einer der vorangegangenen Aufrufe
bereits TRUE zurückgeliefert hat.
Man überlege sich dazu die alternative Schreibweise, bei welcher man
Short Circuit Evaluation nicht ausnutzt. Das gibt nämlich eine ganz
lange und umständlich wirkende if-else-Kette.
Jörg W. schrieb:> Ich erinnere mich noch an Pascal, bei dem man immer schreiben musste:> if someptr <> nil then begin> if @someptr = 42 then …> end>> weil es ebne keine definierte short cut evaluation gab, die garantiert> hätte, dass
Doch, die gibts dort auch. Außerdem wolltest Du ^ schreiben statt @.
1
if (someptr <> nil) and (someptr^ = 42) then begin
2
3
end;
http://www.freepascal.org/docs-html/prog/progsu4.html#x11-100001.2.4
1.2.4 $B or $BOOLEVAL : Complete boolean evaluation
By default, the compiler uses shortcut boolean evaluation, i.e., the
evaluation of a boolean expression is stopped once the result of the
total expression is known with certainty. The {$B } switch can be used
to change this behaviour: if its argument is ON, then the compiler will
always evaluate all terms in the expression. If it is OFF (the default)
then the compiler will only evaluate as many terms as are necessary to
determine the result of the complete expression.
Bernd K. schrieb:>> weil es ebne keine definierte short cut evaluation gab, die garantiert>> hätte, dass>> Doch, die gibts dort auch.
Nicht garantiert. Kann jeder Compiler halten wie'n Dachdecker.
Portabler Code kann sich daher (anders als in C) nicht drauf
verlassen.
> Außerdem wolltest Du ^ schreiben statt @.
Nein, wollte ich nicht, sonst hätte ich das geschrieben. Ich weiß,
was ich will.
Beide Zeichen sind in Pascal äquivalent.
Jörg W. schrieb:> Nein, wollte ich nicht, sonst hätte ich das geschrieben. Ich weiß,> was ich will.>> Beide Zeichen sind in Pascal äquivalent.
Offenbar weißt Du nicht was Du willst, das @ ist der address-of operator
(also das Äquivalent zu & in C) und das ^ ist die
Pointer-Dereferenzierung, (das Äquivalent zu * in C). Also lieber mal
den Ball etwas flacher halten wenn man keine Ahnung hat!
Bernd K. schrieb:> http://www.freepascal.org/docs-html/prog/progsu4.html#x11-100001.2.4>> 1.2.4 $B or $BOOLEVAL : Complete boolean evaluation
Das scheint aber nicht in jedem Dialekt von Pascal garantiert zu sein.
Fußnoten aus https://en.wikipedia.org/wiki/Short-circuit_evaluation :
4 ISO Pascal allows but does not require short-circuiting.
5 ISO-10206 Extended Pascal supports and_then and or_else.
Bei ersterem würde ich das als Programmierer wegen fehlender Sicherheit
nicht nutzen wollen, bei letzterem wurden dafür extra neue
Schlüsselwörter eingeführt...
Bernd K. schrieb:> Offenbar weißt Du nicht was Du willst, das @ ist der address-of operator> (also das Äquivalent zu & in C) und das ^ ist die> Pointer-Dereferenzierung, (das Äquivalent zu * in C). Also lieber mal> den Ball etwas flacher halten wenn man keine Ahnung hat!
Auszug aus
http://www2.informatik.uni-halle.de/lehre/pascal/sprache/pas6ptr.html
----------------------- schnipp -----------------------------------
Mitunter wird auch @ anstelle von ^ verwendet.
Achtung:
In den Borland Pascal Systemen wird - im Widerspruch zum Pascal Standard
- @ als Adreßoperator verwendet (siehe weiter unten).
----------------------- schnapp -----------------------------------
Mit Ahnung hat das also nichts zu tun, sondern eher mit dem verwendeten
Pascal-Dialekt.
Bernd K. schrieb:> Offenbar weißt Du nicht was Du willst, das @ ist der address-of operator> (also das Äquivalent zu & in C) und das ^ ist die> Pointer-Dereferenzierung, (das Äquivalent zu * in C).
Zu den Zeiten, da ich Pascal gemacht habe, war das eine einfach nur
ein Ersatzzeichen des anderen. Hier der entsprechende Abschnitt
aus dem zugehörigen Standard ISO 7185:
1
6.1.9 Lexical alternatives
2
3
The representation for lexical tokens and separators given in 6 .1 .1
4
to 6 .1 .8, except for the character sequences (* and *), shall
5
constitute a reference representation for these tokens and separators.
6
To facilitate the use of Pascal on processors that do not support the
7
reference representation, the following alternatives have been
8
defined. All processors that have the required characters in their
9
character set shall provide both the reference representations and the
10
alternative representations, and the corresponding tokens or
11
separators shall not be distinguished. Provision of the reference
12
representations, and of the alterative token @, shall be
13
implementation-defined. The alternative representations for the
14
tokens shall be
15
16
Reference token Alternative token
17
18
↑ @
19
[ (.
20
] .)
Kocht Freepascal hier sein eigenes Süppchen, oder steht das im
aktuellen Standard anders drin?
Edit: scheint unter diese "implementation-defined"-Klausel zu fallen.
Jörg W. schrieb:> Kocht Freepascal hier sein eigenes Süppchen, oder steht das im> aktuellen Standard anders drin?
Bernd redet offenbar von Borland Pascal oder Freepascal, siehe:
Beitrag "Re: GCC: In welcher Reihenfolge wird if ausgewertet"
Bei Pascal von "Standards" zu sprechen ist offenbar recht schwierig,
wenn sich keiner dran hält. Da ist C wesentlich stringenter.
Frank M. schrieb:> Bei Pascal von "Standards" zu sprechen ist offenbar recht schwierig,> wenn sich keiner dran hält.
Das Problem von Pascal war es eben immer, dass einige in der Praxis
wichtige Dinge von den Standards nicht abgedeckt sind. Die Bildung
einer Adresse eines Objekts ist sowas, Typumwandlung auch.
Damit erfindet dann dort jeder seins.
> Warum? Short cut evaluation ist - wenn man es richtig anzuwenden weiß -> einfach nur praktisch.
Als ob ich was gegen ShortcutEval hätte/gesagt hätte.
Mir geht es um folgendes:
1
if(boolescherAusdruckTrueOderFalse)
2
machwaszuTrue;//Ausduck ergab True
3
else
4
machwaszuFalse;//Ausdruck ergab False
Das IF-Statement führt also dazu dass GENAU machwaszu UND IN JEDEM
FALL NUR machwaszu ausgeführt wird.
(im TO Bsp. schlicht "return ...")
Warum soll ich also machwaszu 2x schreiben, gar in verschiedenen
Verzweigungsäste des Programmflusses?
Der Programmfluss will ja dass machwaszu ohnehin ausgeführt wird.
Dann kommt dieser Fall noch so frech daher dass das Argument von
machwaszu identisch mit der Auswertung der Diskriminanten der IF
Anweisung ist.
Ich erfasse die Absicht als "es geht um eine (1) Aktion", also muss dies
nicht auf mehre Zeilen in 3 Statements (das IF, der THEN Zweig, der ELSE
Zweig) verschleiert werden.
(viel geschwurbel - hoffe mein Punkt kommt nun durch :)
> Das Problem von Pascal war es eben immer, dass einige in der Praxis> wichtige Dinge von den Standards nicht abgedeckt sind.
Darum hat der Pascal-Vater und seine Entourage nicht geruht und die
Entwicklung weitergetrieben.
Mit Modula-2 und Oberon sind dann auch ordentliche Systeme komplett
geschrieben worden.
(so nebenbei: die stark gepiesakte wordyness m. BEGIN...END ist
bereits in M-2 drastisch eliminiert - äätsch)
Wie ist das eigentlich mit C++, ist das da genauso?
IIRC gibt's da ne Schikane wenn && oder || überladen sind, dann greift
nämlich keine Shortcut-Eval.
Quellkothistamin schrieb:> (viel geschwurbel - hoffe mein Punkt kommt nun durch :)
Nur ist das u.U. die Antwort auf die falsche Frage. Wenn man
Beispielcode aus wenigen Zeilen analysiert, dann sollte man bedenken,
dass solcher Code viel unnötigen Kram weglässt. Wodurch der Eindruck
entstehen kann, dass es eine völlig andere bessere Lösung gibt - die
dann aber nur auf den Beispielcode zutrifft, nicht aber auf den Code,
der eigentlich dahinter steht.
Hier war die eigentliche Frage die Bedingung im "if" statement. Nicht
aber, ob man hier true/false-Zweige überhaupt benötigt. Das war mit der
ersten Antwort erledigt. Der Rest des Threads wurde dann ein bizarres
Kaffeesatzlesen darüber, was Kaj vielleicht sonst noch gemeint haben
könnte aber nicht zu fragen wagte und wie man diesen vereinfachten
Beispielcode optisch oder sonstwie optimieren könnte.
Quellkothistamin schrieb:> die stark gepiesakte wordyness m. BEGIN...END ist bereits in M-2> drastisch eliminiert
Hat mich nie gestört. Ich konnte schon Zehnfinger-Blindschreiben,
bevor ich mit Programmieren angefangen habe.
Johann L. schrieb:> IIRC gibt's da ne Schikane wenn && oder || überladen sind, dann greift> nämlich keine Shortcut-Eval.
Möglich, da kenne ich C++ zu wenig. Müsste ich auch im Standard
nachlesen.
Mir reicht es im Moment, wenigstens im C-Standard so einigermaßen
schnell genug das zu finden, was ich gerade suche. :)
@Johann L. (gjlayde) Benutzerseite
>Wie ist das eigentlich mit C++, ist das da genauso?
Keine Ahnung!
Aber trotzdem sollte man von solchen Short Circuit Evaluations eher
vorsichtig Gebrauch machen. Bei reinen logischen Ausdrücken ist das OK
und birgt keine Gefahr, bei Funktionsaufrufen mit Nebeneffekten (Zugriff
auf IO-Register, globale Variablen, etc.) kann sowas ins Auge gehen.
Nicht nur beim originalen Verfasser, auch bei Nachtuzern,
"Pflegepersonal" und last but not least beim Debuggen! Dort sollte man
lieber ein paar Zeilen mehr tippen und die Situation EINDEUTIG im
Quelltext darstellen. Lesbarkeit geht DEUTLICH vor Tippeffizienz!
Jörg W. schrieb:> Johann L. schrieb:>> IIRC gibt's da ne Schikane wenn && oder || überladen sind, dann greift>> nämlich keine Shortcut-Eval.>> Möglich, da kenne ich C++ zu wenig. Müsste ich auch im Standard> nachlesen.
Oder ausprobieren...
Ist so, bei selbstgebautem && kennt mein gcc auch kein short circuit.
Sebastian S. schrieb:> Gab's da nicht einen Compilerschalter bzw. Kommandozeilenparameter, mit> dem man die "Abkürzungen" abschalten kann?
Hoffentlich nicht. In C wäre das ungefähr so sinnvoll wie ein Schalter
zum Vertauschen der Bedeutung von + und -.
Klar: C++ enthält C ziemlich komplett, mit allen Fehlermöglichkeiten.
Und bringt viele neue Möglichkeiten dazu.
Da können die Fehlermöglichkeiten nicht weniger werden.
(PS: Trotzdem kann man in C++ wesentlich fehlerärmer programmieren.
Aber halt nicht, wenn man jeden Mist macht, sondern mit einem passenden
Stil.)
Johann L. schrieb:> Wie ist das eigentlich mit C++, ist das da genauso?
Ja für Builtin Types gibts genauso Short Circuit Evaluation. Erst wenn
man && überläd gibts das nicht mehr. Zum Glück kann man aber operator&&
nur überladen wenn wenigstens eine Klasse oder so dabei ist. Für bool &&
bool kann man also nichts kaputt machen.