Zwei bedingungen in einer if-Abfrage

Gast #7048618
Lesenswert?

Hallo,
ich habe eine Frage zu folgender if-Abfrage
1
if(a() || b()==0)
2
{
3
  ...
4
}

wenn die Funktion a() 1 Zurück gibt, wird die funktion b() noch 
ausgeführt?
Wenn ja/nein, ist das immer so? Oder liegt das am Compiler (oder 
Einstellungen)?

ich habe b() immer in einer neuen if-Abrfage gepackt
1
if(!a())
2
{
3
  if(0==b())
4
  {
5
    ...
6
  }
7
}

aber den oberen Weg auch schon öfters im Code gefunden
Gast #7048790
Lesenswert?

Und weil if kein Funktionsaufruf ist, gehört zwischen das f und die 
öffnende Klammer ein Leerzeichen. (Ja, syntaktisch spielt es keine 
Rolle, schon klar. Aber konsequent ist es.)
</klugschiss>
Gast #7048802
Lesenswert?

Eben wegen der bedingten Ausführung ist die Ausführung von Funktionen - 
abgesehen vom 1. Argument - mit Vorsicht zu genießen: Wenn die Funktion 
nicht nebenwirkungsfrei ist, kann man sich da schwer zu findende 
Programmfehler einbauen. Deshalb verbietet z.B. MISRA solche Konstrukte. 
Der Workaround wäre dann entweder, den Rückgabewert von b() vorher einer 
lokalen Variable zuzuweisen und diese für die Auswertung zu verwenden.
#7048918
Lesenswert?

So rein der Vollständigkeit halber:

Wikipedia weiß (https://de.wikipedia.org/wiki/Kurzschlussauswertung):
> In der Programmiersprache C werden binäre boolesche Ausdrücke mit den Operatoren 
&& und || ausschließlich nach dem Kurzschluss-Prinzip ausgewertet.

> In der Programmiersprache Java stehen die Operator && und || ebenfalls für eine 
Kurzschlussauswertung.
> Zusätzlich existieren jedoch die logischen Operatoren & und |, bei denen die 
Auswertung beider Seiten erzwungen wird.

Und in Delphi gibt es eine Compilerdirektive, mit der zwischen 
Kurzschlussauswertung und "vollständiger" Auswertung umgeschaltet werden 
kann.
https://docwiki.embarcadero.com/RADStudio/Sydney/en/Boolean_short-circuit_evaluation_(Delphi_compiler_directive)
Gast #7048985
Lesenswert?

Nachdenklicher schrieb:
> nd weil if kein Funktionsaufruf ist, gehört zwischen das f und die
> öffnende Klammer ein Leerzeichen. (Ja, syntaktisch spielt es keine
> Rolle, schon klar. Aber konsequent ist es.)
> </klugschiss>

Wer empfiehlt denn sowas? (ich hab nichts dagegen, aber also 
"begründete" Empfehlung hab ich noch nie davon gehört)
Gast #7048992
Lesenswert?

A. S. schrieb:
> Wer empfiehlt denn sowas? (ich hab nichts dagegen, aber also
> "begründete" Empfehlung hab ich noch nie davon gehört)

Mindestens einer von den drölfzig verschiedenen Style Guides, die es für 
C gibt. Hab die Quelle gerade nicht zur Hand. Die Begründung lautete 
auch nicht "if ist keine Funktion", sondern daß vor einer öffnenden 
Klammer eines Funktionsaufrufs kein Leerzeichen steht, aber zwischen 
einem Schlüsselwort und öffnender Klammer eines Ausdrucks. Und das 
trifft auf if (bedingung) ja zu.

Aber gefühlt gibt es ohnehin n+1 verschiedene Stile für C, wobei n die 
Anzahl der Personen, die seit Erfindung der Sprache diese genutzt haben 
ist. ;-)
Gast #7049006
Lesenswert?

Klaus W. schrieb:
> Schlaumaier schrieb:
>> Mach einen vernünftige AND bzw. OR Abfrage wie sich das gehört.
>
> Er macht das vernünftig.

JA aber er versteht die eigene Abfrage nicht.

Im Code darunter steht. :

Marcel schrieb:
> ich habe b() immer in einer neuen if-Abrfage gepacktif(!a())
> {
>   if(0==b())
>   {
>     ...
>   }
> }


Oben macht er eine ODER Abfrage und darunter nochmal eine Spezifische 
Abfrage.

Das kann Programm technisch sogar sinnvoll sein. Aber die Aussage
Marcel schrieb:
> ich habe b() IMMER in einer neuen if-Abrfage gepacktif(!a())

Ist mist.

Sinn macht das nur wenn man A ODER B überprüft und wenn EINER der 
Beiden Bedingungen TRUE / Wahr ist, man in der 2 Abfrage, spezifiziert 
will,   WENN die B - Bedingung wahr ist, man noch etwas anders macht.

Deshalb meine Aussage. So einfach wie IF-THEN Abfragen sind, so 
kompliziert
 kann es sein, die richtige Reaktion zu erzeugen.

Erklärung.

Führerschein = false
Nummernschild = keins

Wenn Fahrzeug = AUTO und Speed > 25 dann
   Führerschein = True
   Nummernschild = klein
   Wenn Speed > 50 dann
     Nummernschild = groß
   end if
end if

Das ist eine vernünftig Abfrage.  Wenn das Fahrzeug ein Fahrrad ist 
fällt die Abfrage komplett aus.

Ist sogar richtig lt. STVO.  Nur bekommt man diese Autos nicht mehr 
zugelassen ;)
Gast #7049016
Lesenswert?

W.S. schrieb:
> Vernünftig ist, unnötigen Seiteneffekten aus dem Wege zu gehen, auch
> wenn es hie und da mal eine zusätzliche Zeile im Quelltext erfordert.

JEPP.

Code muss einfach und übersichtlich bleiben. Weshalb ich 
Verbunds-Abfragen (zu viel AND/OR in einer Zeile) fast immer vermeide.

Lieber mehre Blöcke oder alternativ eine Select CASE abfrage. (k.a. wie 
die in C heißt).

Macht den Code länger aber ich muss mir nicht alle Verwusselungen 
ausdenken.
Gast #7049032
Lesenswert?

Schlaumaier schrieb:
> A. S. schrieb:
>> Wie mit Klammerregeln: Am Anfang setzt man viele, einige
>> ("offensichtlich unnötige") spart man sich später.
>
> Die Klammerregeln sind der Grund wieso ich C hasse wie die Pest.
>
Warum? Lieber eine Klammer zu viel, wenn sie richtig ist. Größer wird 
der entstehende Code dadurch nicht. Später, wenn man sich besser mit dem 
Regeln auskennt, kann man immer noch einsparen...
#7049042
Lesenswert?

Man sollte in einer if Bedingung auch keine Funktionsaufrufe, welche auf 
globale Variablen wirken einbauen. Sodass der Aufruf allein etwas 
bewirkt. Das ist ganz schlechter stil. Schwierig debugbar.

 if (Mach() ==0) OR TerminateThread()==0) { .. }

Einmal laeuft der Thread noch, das andere Mal nicht..
#7049626
Lesenswert?

Apollo M. schrieb:
> besser so ...
> und dann wird a()/b() immer ausgeführt und die short logic umgangen!
>
> if (a() | b()) {
>  ...
> }

Nein. Nein. Nein.

Dann macht man den Aufruf der Funktionen vor dem if und speichert das 
Ergebnis in lokalen Variablen.
Der Compiler optimiert das dann und es bleibt lesbar.

Mit & statt && kann man sonst mächtig auf die Schnauze fallen.
Gast #7049749
Lesenswert?

Die Kurzschlussauswertung ist ganz sicher kein Seiteneffekt oder 
irgendein Obfuscationsthema. Sequencepoints entstehen nicht einfach so.

Es macht wenig Sinn, ein effizientes Konstrukt zu diffamieren, weil 
Anfänger Operatoren verwechseln und deren Wirkung verwechseln könnten. 
Dirk hat ein Beispiel gebracht:

Dirk B. schrieb:
> Damit ist dann auch
> if(a && *a) {
> möglich, wenn a = NULL ist.

Z.B. *p++ ist für Anfänger noch verwirrender: Intuitiv nimmt man (von 
links nach rechts) (*p)++ an. Dann lernt man das und nutzt es auch. Das 
schöne an C: Sooo viele Konstrukte gibt es nicht.
Moderator #7049771
Lesenswert?

Dirk B. schrieb:
> Erlaubt ist in C viel - darum ist C auch für Profis gemacht
> Es zu nutzen, macht einen aber nicht zu einem Profi.

Es hobbymäßig zu nutzen führt auch nicht unbedingt zum Desaster :)

Ich kenne viele Hobbyprogrammierer, die ganz gut mit C zurecht kommen.
Ausnahmen gibt es natürlich immer, auch bei den Profis.
Gast #7050001
Lesenswert?

Schlaumaier schrieb:
> Habe ich oben.

Ja hast Du, habe ich mittlerweile auch gelesen. Wäre besser gewesen Du 
hättest hier diesbezüglich einfach mal die Griffeln still gehalten.
Die Abfrage ist schon so in Ordnung. Allerdings hat er den Fehler bei 
seiner Ausweichlösung. Für seine Ursprungsabfrage
1
if(a() || b()==0)
2
{
3
  ...
4
}
müßte er noch einen else Zweig anhängen. Also so:
1
if( !a() || b()==0 )
2
{
3
  if ( b()==0 )
4
  {
5
    ...
6
  }
7
else
8
{
9
  ...
10
}
Wobei dann in der 2.if-Bedingung und im else-Zweig der gleiche Code 
stehen würde. Ist ja noch unübersichtlicher.
Gast #7050085
Lesenswert?

Zeno schrieb:
> Allerdings hat er den Fehler bei seiner Ausweichlösung

xor schrieb:
> "wenn a oder b" ist nicht das Gleiche wie "wenn nicht a aber b".

Die 2 Beispiele des TOs sind identisch, was den Aufruf von b betrifft.

Ich denke, darum ging es dem TO.

Die entstehenden if/else - Blöcke sind unterschiedlich, maximal den else 
Block des ersten Beispiels könnte man im zweiten Konstrukt nachbilden.

if(a||!b){}else{...} wäre identisch zu if(!a){if(b){...}}

Aber wie gesagt, ich denke dem TO ging es um Kurzschlussauswertung an 
sich.
Gast #7050396
Lesenswert?

Schlaumaier schrieb:
> JA aber er versteht die eigene Abfrage nicht.

ich verstehe die Abfrage schon.
ich es muss nur vermieden werden, dass b() aufgerufen wird, wenn a() 
true zurück gibt. wenn a() false ist, dann muss b() aufgerufen werden.
Daher habe ich es immer in zwei verschiedenen if-Abfragen gepackt, da 
ich mir nicht sicher war, welche Funktion bei
1
if (a() || b()==0)
letztendlich zuerst ausgeführt wird. Nur weil ich es so hinschreibe, 
weiß ich ja nicht was der compiler daraus macht.

xor schrieb:
> Dieser Code hat aber damit nichts zu tun:
 doch, eigentlich schon. siehe erklärung oben.
1
if (!a())
2
{
3
  if (0==b())
4
  {
5
  }
6
}
Auch hier wird b() nur ausgeführt, wenn a() fals zurück gibt.
#7050400
Lesenswert?

Marcel schrieb:
> es muss nur vermieden werden, dass b() aufgerufen wird, wenn a()
> true zurück gibt. wenn a() false ist, dann muss b() aufgerufen werden.

Oh, ich hab das wohl falsch verstanden, ich dachte Du willst 
gewährleisten, das auch b() unbedingt ausgeführt wird.

Ich (seit 30J kein Profi mehr!:) würde bei deiner bewährten Methode 
bleiben. Weil sofort ersichtlich ist, wie das tut.
Gast #7050417
Lesenswert?

Marcel schrieb:
> Auch hier wird b() nur ausgeführt, wenn a() fals zurück gibt.

Die Verwirrung entsteht durch das if. Die Bedingungen (also wann {} 
ausgeführt wird) deiner Beispiele sind verschieden.

Es geht zum Verständnis auch ohne je ein if. Also:

a() || b();

Ist identisch zu

If(!a()) {b();}
Gast #7050433
Lesenswert?

A. S. schrieb:
> Die Verwirrung entsteht durch das if. Die Bedingungen (also wann {}
> ausgeführt wird) deiner Beispiele sind verschieden.
>
> Es geht zum Verständnis auch ohne je ein if. Also:
>
> a() || b();
>
> Ist identisch zu
>
> If(!a()) {b();}

da habe ich mich wieder falsch ausgedrückt :(
1
if (!a())
2
{
3
  if (0==b())
4
  {
5
    code
6
  }
7
}

der code in der Funktion b() soll nur ausgefürht werden, wenn a() false 
zurück gibt.
Desweiteren soll der allgemeine Code nur ausgeführt werden, wenn b() 0 
zurück gibt.

wenn b() 0 zurück gibt, wird a() ab sofort true zurück geben (bis man 
eine neue funktion aufruft um das wieder rückgängig zu machen).

b() darf aber auch nur einmalig ausgeführt werden (bis man eine neue 
funktion aufruft um das wieder rückgängig zu machen).

aber wenn es ja im standard drinn steht, dass bei
1
if (a() || b()==0)
b() nicht mehr ausgeführt wird, wenn a() true ist, ist ja alles in 
ordnung.

Mein Problem war, dass ich mir nicht sicher bin, ob der compiler auch 
diese reihenfolge behält und nicht erst b() ausführt und dann a().

Nur weil ich es so hinschreibe, heißt es ja noch nicht, dass der 
compiler diese Reihenfolge auch behält (?), oder doch?
Gast #7050473
Lesenswert?

A.S. schrieb:
> Die 2 Beispiele des TOs sind identisch, was den Aufruf von b betrifft.
>
> Ich denke, darum ging es dem TO.

Aber eben nur was b betrifft. In der Ursprungsbedingung soll aber auch a 
ausgeführt werden wenn es wahr ist und das ist bei seiner 2. Lösung 
definitiv nicht der Fall. Seine zweite Lösung beschreibt eigentlich eine 
UND-Verknüpfung !a && b.
Gast #7050559
Lesenswert?

Marcel schrieb:
> Nur weil ich es so hinschreibe, heißt es ja noch nicht, dass der
> compiler diese Reihenfolge auch behält (?), oder doch?

Apollo M. schrieb:
> A. S. schrieb:
>
>> Sequencepoints entstehen nicht einfach so
>
> Korrekt, das ist der Schlüsselbegriff


Also ja, es ist für && und ||  in der Reihenfolge garantiert und das mit 
Absicht und weitere Infos unter dem Schlüsselwort.

Nur zur Einordnung: ein = ist kein sequencepoint und es ist nicht klar, 
ob links oder rechts davon zuerst ausgeführt wird, z.b. wenn auf beiden 
Seiten ein Funktionsaufruf oder ein ++ steht.
Gast #7050597
Lesenswert?

Marcel schrieb:
> aber wenn es ja im standard drinn steht, dass bei1if (a() || b()==0)
> b() nicht mehr ausgeführt wird, wenn a() true ist, ist ja alles in
> ordnung.

Du hast an dieser Stelle die falsche Logik gewählt. b() wird zwar hier 
bei a() true nicht ausgeführt weil die boolsche Bedingung bereits 
erfüllt ist. Dennoch wird der allgemeine Code ausgeführt. Du möchtest 
den allgemeinen Code aber nur ausführen wenn zu dem auch noch b() false 
ist.   Da wäre Dein 2. Ansatz der Richtige. Du könntest es über eine 
UND-Verknüpfung machen
1
if ( !a() && !b() ) { code }
Wenn a() hier true ist wird b() nicht mehr ausgeführt, weil !a() false 
ist ist und somit das Ergebnis der UND-Verknüpfung bereits feststeht.

Ich weis jetzt nicht ob man bei C die Kurzschlußauswertung abschalten 
kann, bei Delphi z.B. geht das und dann würden boolsche Ausdrücke immer 
vollständig ausgewertet werden, auch dann wenn das Ergebnis bereits fest 
steht. WEnn Du es sicher machen willst, also unabhängig von 
irgendwelchen Compilereinstellungen, dann mach es so:
1
if ( !a() )
2
  if ( !b() )
3
  {
4
     code
5
  }
So wird b nur dann ausgeführt wenn a() false ist.
Gast #7050793
Lesenswert?

Zeno schrieb:
> A. S. schrieb:
>> Es geht um C, nicht Delfi. In C ist es nicht abschaltbar.
> Des Lesens bist Du schon mächtig? Ich hatte Delphi als Bespiel benannt,
> könnte ja sein das das beim C-Compiler auch möglich ist, weshalb ich ja
> auch im Konjunktiv geschrieben hatte.

Nachdem die Frage des TOs mehrfach eindeutig beantwortet wurde, 
empfiehlst Du, das lieber zu ignorieren, weil es in C ja wie in Delphi 
sein könnte.

Ich habe es für Dich klargestellt, weil Du den Thread wohl nur teilweise 
gelesen hast.
Moderator #7050819
Lesenswert?

Eine Compileroption für die Deaktivierung der Kurzschlussauswertung
würde vermutlich ziemlich viel Verwirrung stiften, weil beim Lesen des
Quellcodes niemand erwartet, dass die standardisierten Regeln plötzlich
nicht mehr gelten.

Wenn man tatsächlich eine vollständige Auswertung boolescher Ausdrücke
möchte, schreibt man diese einfach etwas anders hin, also bspw.
1
(bool)a() | (bool)b()

statt
1
a() || b()

Dann erkennt jeder sofort die Absicht dahinter.

Alternativ kann man auch – wie oben bereits vorgeschlagen – die
Ergebnisse von a() und b() in temporäre Variablen schreiben und diese
anschließend mit || verknüpfen.

In den allermeisten Fällen stellt die Kurzschlussauswertung aber einen
Vorteil dar, so dass man der Umweg über Bitoperationen oder temporäre
Variablen nur selten benötigt.

Für Pascal-Derivate, in denen zwischen Kurzschluss- und vollständiger
Auswertung unterschieden werden soll, würde sich die Unterscheidung
mittels Zusatz zum Operatornamen nach ISO 10206 (Extended Pascal)
anbieten, also "and" und "or" für vollständige  und "and then" und "or
else" für Kurzschlussauswertung. Das wäre auf jeden Fall sauberer als
die Umschaltung per Compileroption.
#7050845
Lesenswert?

Die Kurzschlussauswertung ist dann richtig, wenn die Funktionen a() und 
b() seiteneffektfrei sind.
Da sie eine leere Parameterliste haben und offensichtlich freie 
Funktionen sind, sind es also entweder freie Beobachter-Funktionen (als 
Elementfunktionen wäre sie dann const) für globale Datenstrukturen oder 
sie haben einen Seiteneffekt darauf. Letzteres ist software-technisch 
eine Katastrophe, doch meistens geht es aus dem Namen hervor, was hier 
jetzt nicht ersichtlich ist.
Beitrag #7050997 wurde von einem Moderator gelöscht.
Gast #7051082
Lesenswert?

Wilhelm M. schrieb:

> Die Kurzschlussauswertung ist [...]

...begrifflich genau solcher Schwachsinn wie der
bürstenlose Gleichstrommotor oder der integrierte
Koprozessor.

"&&" ist kein boolescher Operator (Beweis auf Anfrage) --
sondern eine Kurzschreibweise für geschachtelte Bedingungen.
(Meines Wissens definiert der Standard das auch genau so.)


Es scheint zu den besonders beliebten Teilen der C-Folklore
zu gehören, nützliche Dinge mit möglichst suggestiven, aber
irreführenden Namen zu bezeichnen...
Gast #7051085
Lesenswert?

Zeno schrieb im Beitrag #7050997:

> Yalu X. schrieb:
>
>> Das wäre auf jeden Fall sauberer als die Umschaltung per
>> Compileroption.
>
> Was ist daran unsauber?

Die "Kurzschlussauswertung" steht seit je her im C-Standard.
Ein Compilerschalter dafür hätte die Bedeutung "Standard
respektieren? Ja [ ]   Nein [ ] ".


> Bei Delphi

"Jaja, so hoch ist noch niemand gesprungen, aber wir machen
hier WEITSPRUNG ..."

Die Frage des TO bezog sich auf C, und die Antworten beziehen
sich -- Überraschung! -- auch auf C...
Gast #7051098
Lesenswert?

Yalu X. schrieb:

> Für Pascal-Derivate, in denen zwischen Kurzschluss- und
> vollständiger Auswertung unterschieden werden soll, würde
> sich die Unterscheidung mittels Zusatz zum Operatornamen
> nach ISO 10206 (Extended Pascal) anbieten, also "and" und
> "or" für vollständige  und "and then" und "or else" [...]

"Unsere Lösung -- ihr Problem!"

Wenn ich "Kurzschluss-Auswertung" haben will, lese ich den
Standard einfach von hinten nach vorn und schreibe zwei
(oder mehr) Bedingungen auf zwei (oder mehr) Zeilen...

Die Verachtung, dass kein "echter" Programmierer das je so
machen würde, kann ich leicht in Kauf nehmen, da sowieso
kein "echter" Programmierer je Pascal verwenden würde...
Moderator #7051183
Lesenswert?

Zeno schrieb im Beitrag #7050997:
> arrogantes A........, Kacke

Was ist denn dir so kurz vor Mitternacht noch über die Leber gelaufen?

Zeno schrieb im Beitrag #7050997:
> Das mit "and then" und "or else" ist wieder mal so eine GNU-Kacke (auch
> wenn's ne ISO ist) und ein Sonderweg.

Du meinst also, der Entwickler von GNU Pascal, der gerade mal 1 Jahr vor
der Veröffentlichung des ISO-Standards die Version 0.01 fertiggestellt
hat, hatte tatsächlich einen so großen Einfluss auf das ISO-Gremium,
dass er kurz vor Ladenschluss das and_then und or_else noch erfolgreich
in den Standard hineinboxen konnte? Ich glaube, du hast überhaupt keine
Vorstellung davon, wie so eine Normung abläuft :D

> Weder in den mir bekannten Delphivarianten noch Freepascalvarianten
> wird so ein Mist gemacht.

Borland hat sich auch mit Turbo-Pascal noch nie an irgendwelche
Standards gehalten, warum sollten sie es mit Delphi plötzlich tun? Und
Free Pascal implementiert im Wesentlichen dieselbe Sprache, die auch
Delphi zugrundeliegt.

> Ich habe es gerade auch noch mal gegoogelt und das scheint wirklich
> ein Alleinstellungsmerkal bei GNU zu sein.

Das ist kein Wunder, denn zum Zeitpunkt der ersten Veröffentlichung des
ISO-Standards (1990) hat Pascal schon weitgehend ausgedient, so dass es
dafür so gut wie keine Neuentwicklungen von Compilern mehr gab. Nur
Borland und später Embarcadero pflegten Turbo Pascal (das später in
Delphi aufging) für einen sehr überschaubaren Kundenkreis noch weiter.
Für Embarcadero gilt aber nach wie vor:

> Die können sich an keine Standards halten und müssen immerwieder ihr
> eigenes Süppchen kochen - ist bei den Truppenteilen nichts Neues.

Das ist ja mittlerweile auch völlig egal: Da die Firma den praktisch
einzigen noch verbleibenden Pascal-Compiler anbietet (GNU Pascal ist
längst eingestellt und Free Pascal ahmt nur nach), braucht es auch keine
internationalen Standards, und Kompatibilität zu irgendetwas ist
ebenfalls kein Thema, da dieses Irgendetwas längst nicht mehr existiert.

Das "and_then" und "or_else" gibt es übrigens nach wie vor in Ada (ohne
die Underscores), als gängige Erweiterung in strukturiertem Text
(SPS-Programmiersprache nach EN/IEC 61131-3) und als "AndAlso" und
"OrElse" in VB.NET:

  https://en.wikipedia.org/wiki/Short-circuit_evaluation

Jede der genannten Sprachen für sich hat einen Nutzerkreis, der um ein
Vielfaches größer ist als der von Delphi und Free Pascal zusammen. Die
Verwendung spezieller Operatoren für die Kurzschlussauswertung ist
entgegen deiner Meinung also keineswegs auf GNU beschränkt.

Aber vielleicht geht es dir heute morgen ja schon wieder besser :)
Moderator #7051197
Lesenswert?

Egon D. schrieb:
> "&&" ist kein boolescher Operator (Beweis auf Anfrage) --

Geschenkt. Das ist eine Frage der Definition, und Definitionen
müssen und können nicht bewiesen oder widerlegt werden.

> sondern eine Kurzschreibweise für geschachtelte Bedingungen.

Ersetze "sondern" durch "und auch", dann stimmt es eher, wobei ich mir
unter einer "geschachtelten Bedingung" etwas anderes vorstelle als du,
nämlich eine logische Operation, bei der mindestens ein Operand wieder
eine logischer Operation ist.

> (Meines Wissens definiert der Standard das auch genau so.)

Im Standard werden sie "logical operators" genannt. Da die (klassische)
Logik eine Boolesche Algebra darstellt, ist auch "boolesche Operatoren"
in Ordnung, nur weniger spezifisch, da bspw. auch die Mengenalgebra eine
Boolesche Algebra ist.
Gast #7051281
Lesenswert?

Diese (teilweise schöne) Diskussion hier ist nur ein weiterer Beleg 
dafür, dass die Zukunft den Funktionalen Programmiersprachen gehört.

Am besten wäre immer noch Lambda-Kalkül... ;)

Church und Kleene waren ihrer Zeit nun schon bald 100 Jahre voraus.
Gast #7051320
Lesenswert?

> dass die Zukunft den Funktionalen Programmiersprachen gehört

Nicht so ganz - das Problem sind diese neumodische Sachen, wie Parser, 
die jede BNF in Bäume umwandeln können.

In der guten alten Lisp Klammerschreibweise können solche Fragen erst 
gar nicht auftauchen.

Wenn du dagegen die C Syntax für eine funktionale Sprache nutzt, 
bekommst du dort auch die selbe Verwirrung.
Gast #7051325
Lesenswert?

Egon D. schrieb:
>> Bei Delphi
>
> "Jaja, so hoch ist noch niemand gesprungen, aber wir machen
> hier WEITSPRUNG ..."
>
> Die Frage des TO bezog sich auf C, und die Antworten beziehen
> sich -- Überraschung! -- auch auf C...
Egon D. schrieb:
> Die Verachtung, dass kein "echter" Programmierer das je so
> machen würde, kann ich leicht in Kauf nehmen, da sowieso
> kein "echter" Programmierer je Pascal verwenden würde...
Na Egon auch Nase etwas "hoch trag". Macht aber nichts jetzt wissen alle 
das Du ein echter Programmierer bist, weil Du nur C programmierst. Dein 
Statement ist ja wohl auch mal wieder an Arroganz kaum zu toppen.

Yalu X. schrieb:
> Was ist denn dir so kurz vor Mitternacht noch über die Leber gelaufen?
Dann schau mal was A.S. in seinem Post geschrieben hat, auf den ich 
geantwortet habe und schau evtl. auch noch mal auf meinen Post auf den 
er geantwortet hat.
Da kann man auch anders antworten und nicht so wie A.S. das getan hat. 
Ein schlichtes "in C ist das nicht abschaltbar" oder so ähnlich wäre 
völlig ausreichend gewesen und hätte meine indirekt gestellte Frage 
vollständig beantwortet. Statt dessen meint er, er müsse sein Gegenüber 
als ein bissel doof darstellen.
Aber lassen wir das und kehren lieber zum Thema zurück.

Yalu X. schrieb:
> Du meinst also, der Entwickler von GNU Pascal, der gerade mal 1 Jahr vor
> der Veröffentlichung des ISO-Standards die Version 0.01 fertiggestellt
> hat, hatte tatsächlich einen so großen Einfluss auf das ISO-Gremium
Das habe ich so nicht geschrieben. Da reicht es wenn einer im Gremium 
der Meinung ist, das dieses Feature top ist. Wenn er dann für seine 
Ansichten Mehrheiten gewinnen kann, dann wird so etwas eben in die Norm 
auf genommen. Nicht immer ist aber das was derartige Gremien beschließen 
immer sinnvoll, ich denke das wissen wir nur zu gut auch aus vielen 
andern Bereichen. Kleines Beispiel gefällig: Verordnung 1677/88/EWG, 
auch als Gurkenverordnung bekannt. Dort wird ja bekanntlich festgelegt 
das die Krümmung einer Gurke nich mehr wie 10mm betragen darf - dabei 
wissen alle Gurkenesser das krumme Gurken viel besser schmecken :-).

Yalu X. schrieb:
> Borland hat sich auch mit Turbo-Pascal noch nie an irgendwelche
> Standards gehalten, warum sollten sie es mit Delphi plötzlich tun? Und
> Free Pascal implementiert im Wesentlichen dieselbe Sprache, die auch
> Delphi zugrundeliegt.
Borland ist nicht so weit weg vom Standard. Ein großer Sprung 
diesbezüglich wurde eigenlich erst in Delphi gemacht. Den Datentyp 
Variant z.B. gibt es im Urpascal von N.Wirth und ich meine auch in 
Borland Pascal nicht. Zu diesem Zeitpunkt war allerdings OLE auch noch 
kein Thema. Ich bin mir noch nicht einmal sicher ob es bei Wirth schon 
Objekte gab. Das fand dann erst Einzug durch die Zusammenarbeit mit 
Apple. Auch die in diesem Thread besprochene Kurzschlußauswertung ist 
kein Feature des Urpascal und wurde von Wirth sogar explizit 
ausgeschlossen - er wird seine Gründe gehabt haben.
Aber auch Pascal entwickelt sich halt weiter, auch wenn das hier von 
einigen als Alleinstellungsmerkmal von C geseheen wird, und kommt 
letztendlich da auch nicht umhin. Auf "and then" und "or else" kann aber 
gern verzichtet werden. Das ist so eine Krücke die man bei Java mit & 
und | im Gegensatz zu && und || eingeführt hat.

Yalu X. schrieb:
> ... hat Pascal schon weitgehend ausgedient,
Das dürfte der Wunsch vieler C-Programmierer sein. Aber merke tod 
Geglaubte leben meist länger. Delphi ist noch sehr lebendig, gerade im 
September ist eine neu Version (RAD Studio 11) heraus gekommen. Meinst 
Du die würden da auch nur einen Cent Entwicklungskosten rein stecken, 
wenn da am Ende nichts rum kommen würde? Ganz sicher nicht. Die 
Delphi/Freepascal/Lazerus Commutity ist auch recht agil.

Yalu X. schrieb:
> für einen sehr überschaubaren Kundenkreis noch weiter
Es gibt deutlich mehr Kunden bzw. Software die auf Delphi setzen als Du 
zu glauben scheinst.

Yalu X. schrieb:
> Das "and_then" und "or_else" gibt es übrigens nach wie vor in Ada (ohne
> die Underscores), als gängige Erweiterung in strukturiertem Text
> (SPS-Programmiersprache nach EN/IEC 61131-3) und als "AndAlso" und
> "OrElse" in VB.NET:
>
>   https://en.wikipedia.org/wiki/Short-circuit_evaluation
>
> Jede der genannten Sprachen für sich hat einen Nutzerkreis, der um ein
> Vielfaches größer ist als der von Delphi und Free Pascal zusammen.
Das ist auch wieder so eine Behauptung Deinerseits. Das Pascal im 
Vergleich zu Phython, Java und allem was irgendwie C heißt schlechter 
abschneidet steht außer Diskussion, aber so pauschal wie Du das nun 
wieder mal schreibst ist es eben auch nicht.

Yalu X. schrieb:
> Aber vielleicht geht es dir heute morgen ja schon wieder besser
Kann ich so nicht sagen - mir ging es gestern durchaus nicht schlechter 
als heute.

Yalu X. schrieb:
> Jede der genannten Sprachen für sich hat einen Nutzerkreis
Diesen Teil des Satze würde ich so sogar schon fast unterschreiben und 
noch etwas ergänzen: "und ihre Daseinsberechtigung."
Ja ich weis jetzt treten gleich wieder einige eingefleichte 
C-Programmierer auf den Plan, die meinen das C das Evangelium ist.
Moderator #7051342
Lesenswert?

Einer schrieb:
> Diese (teilweise schöne) Diskussion hier ist nur ein weiterer Beleg
> dafür, dass die Zukunft den Funktionalen Programmiersprachen gehört.

Ja, damit wären die hier diskutierten und auch viele andere Probleme
komplett aus der Welt geschafft. Allerdings ist der Weg dorthin noch mit
großen Hindernissen gepflastert, das größte davon heißt Neophobie.

Da immer mehr gängige imperative Programmiersprachen wie C++, Rust und
Python mit funktionalen Elementen versehen werden, wäre zu hoffen, dass
dies vielleicht zu einer langsamen, aber stetigen Migration zur
funktionale Programmierung führt, bei der niemand ins kalte Wasser
geschmissen wird.

So etwas ähnliches ist ja bei der objektorientierten Programmierung
geschehen, die Dank dem sanften Umstieg mittels C++ oder Python
mittlerweile zum Mainstream gehört.

Allerdings ist der Sprung von einer imperativen zu einem deklarativen
Programmierparadigma, wie es die FP umsetzt, ein gutes Stück größer
als zwischen zwei verschiedenen Paradigmen innerhalb der imperativen
Welt. Als Hilfe bei diesem Sprung stellen auch die o.g. funktional
angehauchten imperativen Sprachen zwar ein ein Trampolin dar, aber
leider nur eins mit teilweise gebrochenen Federn.

Mal schauen, was die nächsten 20 Jahre bringen werden :)


Noch ein Kommentar schrieb:
> Wenn du dagegen die C Syntax für eine funktionale Sprache nutzt,
> bekommst du dort auch die selbe Verwirrung.

Das Problem des TE war nicht die Syntax, sondern die Semantik, und diese
ist in funktionalen Sprachen – unabhängig von der verwendeten Syntax –
tatsächlich sehr viel einfacher.
#7051668
Lesenswert?

Yalu X. schrieb:
> Alternativ kann man auch – wie oben bereits vorgeschlagen – die
> Ergebnisse von a() und b() in temporäre Variablen schreiben und diese
> anschließend mit || verknüpfen.

Das wäre ein sehr dummer Compiler und tatsächlich findet das nur bei O0 
statt.

Der Compiler wird auch dies bei der Optimierungsstufe > O1 wieder in den 
Code einer Kurzschlussauswertung umwandeln. Es sei denn, man macht die 
temp. Variablen volatile.
Gast #7051700
Lesenswert?

Wilhelm M. schrieb:
> Yalu X. schrieb:
>> Alternativ kann man auch – wie oben bereits vorgeschlagen – die
>> Ergebnisse von a() und b() in temporäre Variablen schreiben und diese
>> anschließend mit || verknüpfen.
>
> Das wäre ein sehr dummer Compiler und tatsächlich findet das nur bei O0
> statt.
>
> Der Compiler wird auch dies bei der Optimierungsstufe > O1 wieder in den
> Code einer Kurzschlussauswertung umwandeln. Es sei denn, man macht die
> temp. Variablen volatile.

Hmmm, ich habe hier einen »dummen Compiler«, der macht's richtig bei 
jeder Optimierungsstufe. Aber bitte jetzt nicht denken das ich 
überrascht war…
1
bool a(void) {
2
    puts("a()");
3
    return 1;
4
}
5
bool b(void) {
6
    puts("b()");
7
    return 1;
8
}
9
int main(void) {
10
    auto resa = a();
11
    auto resb = b();
12
    if (resa || resb) {
13
        puts("Hey");
14
    }
15
    return 0;
16
}
Für alle O0…O3 und auch Os gibt's "a() b() Hey"
Gast #7051713
Lesenswert?

Wilhelm M. schrieb:
> Norbert schrieb:
>> Hmmm, ich habe hier einen »dummen Compiler«, der macht's richtig bei
>> jeder Optimierungsstufe.
>
> puts(...) macht intern letztendlich einen Zugriff auf volatile. Dieser
> darf nicht wegoptimiert werden, was ich auch oben geschrieben hatte.
> Entferne das puts() und schau Dir das Ergebnis im CompilerExplorer an.

Also irgend etwas müssen die Funktionen schon machen damit sie nicht weg 
optimiert werden. Aber auch das alleinige hoch zählen einer globalen 
Variablen funktioniert problemlos.
Wenn nichts, aber auch gar nichts in den Funktionen drin steht, warum 
soll man sie dann im executable belassen?
#7051732
Lesenswert?

Norbert schrieb:
> Also irgend etwas müssen die Funktionen schon machen damit sie nicht weg
> optimiert werden.

Wenn sie auf eine programm-globale Variable zugreifen, werden sie nicht 
wegoptimiert.

Wenn Du in beiden Funktionen eine globale Variable incrementierst, 
erzeugst Du eine Abhängigkeit, die natürlich auch nicht wegoptmiert 
werden darf. Du wirst allerdings feststellen, dass ein re-order 
stattfindet, d.h. das Inkrement in a() und b() wird zu einem Inkrement 
zusammen gefasst. Dann hast Du letztlich Äpfel mit Birnen verglichen.
Gast #7051758
Lesenswert?

Wilhelm M. schrieb:
> Du wirst allerdings feststellen, dass ein re-order
> stattfindet, d.h. das Inkrement in a() und b() wird zu einem Inkrement
> zusammen gefasst.
Du meine Güte, ja, gerne. Weil's keinen Unterschied macht!
Sobald es einen Unterschied machen würde, zB. weil erst etwas in PORTA 
und in der nächsten Funktion etwas in PORTB geschrieben wird, dann 
wird's auch genau so ausgeführt.
Wo bitte ist das Problem? Bitte um Beispielcode wo der Compiler einen 
falschen Programmablauf verursachen würde. Danke!
#7051764
Lesenswert?

Norbert schrieb:
> Du meine Güte, ja, gerne. Weil's keinen Unterschied macht!
> Sobald es einen Unterschied machen würde, zB. weil erst etwas in PORTA
> und in der nächsten Funktion etwas in PORTB geschrieben wird, dann
> wird's auch genau so ausgeführt.

Ja, das sage ich ja die ganze Zeit: volatile.

Andernfalls hast Du wie in Deinem (modifizierten) Beispiel die 
Modifikation eines Objektes: sequence-point.

Norbert schrieb:
> Wo bitte ist das Problem? Bitte um Beispielcode wo der Compiler einen
> falschen Programmablauf verursachen würde.

Ich rede gar nicht von einem Problem. Und schon gar nicht von einem 
Fehler des Compilers.

Solange a() und b() keine sequence-points enthalten, nützt auch das 
Einführen von lokalen Variablen nicht, um ein shortcut zu verhindern. 
Das war meine Aussage oben.
#7051868
Lesenswert?

Wilhelm M. schrieb:
> Das wäre ein sehr dummer Compiler und tatsächlich
> findet das nur bei O0 statt.

Du redest rückwärts. Wenn ich a() und b() temporären Variablen zuweise 
und dann verknüpfe, dann werden a() und b() auch ausgeführt, denn deren 
Nebeneffekte müssen in dieser Reihenfolge auftreten.

Wenn der Compiler natürlich beweisen kann, dass es keine Nebeneffekte 
gibt, dann darf er dadran gerne rumoptimieren.

Die Aussage, dass das nur bei O0 stattfindet, ist nämlich genau dann 
falsch, wenn die Funktion nicht pure ist (aka "der Normalfall"). Alles 
andere wäre eine Verletzung des Standards.
Gast #7051978
Lesenswert?

Zeno schrieb:
> Dann schau mal was A.S. in seinem Post geschrieben hat, auf den ich
> geantwortet habe und schau evtl. auch noch mal auf meinen Post auf den
> er geantwortet hat.
> Da kann man auch anders antworten und nicht so wie A.S. das getan hat.
> Ein schlichtes *"in C ist das nicht abschaltbar"* oder so ähnlich wäre
> völlig ausreichend gewesen und hätte meine indirekt gestellte Frage
> vollständig beantwortet. Statt dessen meint er, er müsse sein Gegenüber
> als ein bissel doof darstellen.

Sorry, Zeno, aber Du bist ausgerastet (im Sinne von persönlich 
beleidigend geworden), weil ich schrieb (und das ist der vollständige 
Post):

A. S. schrieb:
> Es geht um C, nicht Delfi. In C ist es nicht abschaltbar.

Der zweite Satz ist identisch zu dem, was Du gut gefunden hättest. Du 
entzündest Dich also an meinem: es geht um C, nicht Delfi.
#7051996
Lesenswert?

Wilhelm M. schrieb:
> Solange a() und b() keine sequence-points enthalten, nützt auch das
> Einführen von lokalen Variablen nicht, um ein shortcut zu verhindern.
> Das war meine Aussage oben.

Dann gibt es allerdings auch keinen Grund, es verhindern zu wollen. Das 
ist auch keine shortcut evaluation, sondern schlicht Teil der normalen 
Optimierung. Wenn die Funktion keinen erkennbaren Effekt hat, kann sie 
wegoptimiert werden, ganz egal ob da ein || steht, oder nicht.
#7052018
Lesenswert?

Was ich meinte, war einfach folgendes.

Die Variante mit den lokalen Variablen erzwingt keine Auswertung der 
Funktion b(), wenn b() keinen sequence-point enthält. Das ist immer dann 
der Fall, wenn sie eine reine Prädikat-Funktion ist. Und das hat nichts 
mit dem Wegoptimieren der Funktion zu tun.
Folgendes Beispiel:
1
#include <stdio.h>
2

3
bool a1 = true;
4
bool b1 = true;
5

6
static bool a() {
7
    return a1;
8
}
9
static bool b() {
10
    return b1;
11
}
12
static bool noShortCutOr(const bool a, const bool b) {
13
    return a || b;
14
}
15
int main() {
16
//    if (noShortCutOr(a(), b())) {
17
//        puts("Hey");
18
//    }
19
    auto resa = a();
20
    auto resb = b();    
21

22
    if (resa || resb) {
23
        puts("Hey");
24
    }
25
}
26
[c]
27

28
ergibt
29

30
[c]
31
.LC0:
32
        .string "Hey"
33
main:
34
        cmp     BYTE PTR a1[rip], 0
35
        jne     .L4
36
        cmp     BYTE PTR b1[rip], 0
37
        je      .L6
38
.L4:
39
        push    rax
40
        mov     edi, OFFSET FLAT:.LC0
41
        call    puts
42
        xor     eax, eax
43
        pop     rdx
44
        ret
45
.L6:
46
        xor     eax, eax
47
        ret
48
b1:
49
        .byte   1
50
a1:
51
        .byte   1

Durch den Zugriff auf die beiden programm-globalen Variablen a1 und b1 
können die Funktionen nicht wegoptimiert werden. Der Zugriff findet 
statt, wie man sieht. Das Wegoptimieren würde allerdings passieren, wenn 
sie TU-lokal sind, also static.
Man sieht hier, dass es genau die Kurzschlussauswertung ist. Die ist 
dann im Assembler identisch zu:
1
#include <stdio.h>
2

3
bool a1 = true;
4
bool b1 = true;
5

6
static bool a() {
7
    return a1;
8
}
9
static bool b() {
10
    return b1;
11
}
12
int main() {
13
    if (a() || b()) {
14
        puts("Hey");
15
    }
16
}

ergibt auch wieder:
1
.LC0:
2
        .string "Hey"
3
main:
4
        cmp     BYTE PTR a1[rip], 0
5
        jne     .L2
6
        cmp     BYTE PTR b1[rip], 0
7
        je      .L5
8
.L2:
9
        push    rax
10
        mov     edi, OFFSET FLAT:.LC0
11
        call    puts
12
        xor     eax, eax
13
        pop     rdx
14
        ret
15
.L5:
16
        xor     eax, eax
17
        ret
18
b1:
19
        .byte   1
20
a1:
21
        .byte   1

Also, die Aussage, dass das Einführen von lokalen Variablen eine 
Auswertung von b() erzwingt ist allgemein falsch. Das funktioniert nur, 
wenn ein sequence-point eingeführt wird. Wie vorher schon geschrieben, 
kann dies geschehen durch

1) Zugriff auf volatile Objekte,
2) Modifikation eines Objektes
3) ...
4) ... (die Liste ist lang)

Bei 1) ist es eh klar, dass das dann den gewünschten Effekt hat 
(Beispiel mit puts() in der Funktion a() und b()). Neben dem erzwungenen 
Zugriff kann auch kein reorder mehr stattfinden.
Und bei 2) führt man einen sequence-point ein, und damit ist es keine 
Prädikat-Funktion mehr. Als Elementfunktion wäre die Funktion dann eben 
nicht mehr const-qualified (ein starkes Argument dafür, die 
Unterscheidung zwischen Beobachterfunktionen und Modifikatoren 
konsequent zu machen und damit auf die const-correctness zu achten. Aber 
das sollte ja eh jedem klar sein).

P.S.: da die obige Liste, welche Aktionen zu einem sequence-point sehr 
lang ist, mag zu der Aussage verleiten, dass das mit den lokalen 
Variablen immer funktioniert ...
Gast #7052107
Lesenswert?

Wilhelm M. schrieb:
> Das Wegoptimieren würde allerdings passieren, wenn
> sie TU-lokal sind, also static.
> Man sieht hier, dass es genau die Kurzschlussauswertung ist. Die ist
> dann im Assembler identisch zu:

Ich vermute einfach nur einen lazy Optimierer. Da a1 und b1 bekannt und 
konstant sind (in Deinem Code-Beispiel), könnte der Compiler m.E. auf 
beide Aufrufe verzichten.

Wenn Du zwei globale Funktionen Ma1 und Mb1 einführst, die a1 und b1 
modifizieren (void Ma1(bool b){a1=b;}), dann sollte der Optimierer 
wieder beide Funktionen aufrufen.

P.S.: (wobei ich schwimme, was "vor" main erlaubt wäre, also ob "main" 
besonders ist).
Moderator #7052154
Lesenswert?

Wilhelm M. schrieb:
> Yalu X. schrieb:
>> Alternativ kann man auch – wie oben bereits vorgeschlagen – die
>> Ergebnisse von a() und b() in temporäre Variablen schreiben und diese
>> anschließend mit || verknüpfen.
>
> Das wäre ein sehr dummer Compiler und tatsächlich findet das nur bei O0
> statt.
>
> Der Compiler wird auch dies bei der Optimierungsstufe > O1 wieder in den
> Code einer Kurzschlussauswertung umwandeln. Es sei denn, man macht die
> temp. Variablen volatile.

Natürlich ist klar, dass der Compiler keine vollständige Auswertung
macht, wenn er erkennen kann, dass es auch einfacher geht. Das ist immer
so, nicht nur bei der Kurzschlussauswertung:

  https://en.cppreference.com/w/cpp/language/as_if

Die ganze diesbezügliche (und IMHO unnötige) Diskussion ist wohl darauf
zurückzuführen, dass ich mich oben ungenau ausgedrückt habe:

Yalu X. schrieb:
> Wenn man tatsächlich eine vollständige Auswertung boolescher Ausdrücke
> möchte, schreibt man diese einfach etwas anders hin, also bspw.
>
> (bool)a() | (bool)b()
>
> ...
>
> Alternativ kann man auch – wie oben bereits vorgeschlagen – die
> Ergebnisse von a() und b() in temporäre Variablen schreiben und diese
> anschließend mit || verknüpfen.

Ich hätte den Satz besser so formulieren sollen:

Wenn man dasselbe Verhalten wie bei einer vollständigen Auswertung
boolescher Ausdrücke möchte, ...
Gast #7052309
Lesenswert?

A.S. schrieb:
> Sorry, Zeno, aber Du bist ausgerastet (im Sinne von persönlich
> beleidigend geworden), weil ich schrieb (und das ist der vollständige
> Post):
>
> A. S. schrieb:
>> Es geht um C, nicht Delfi. In C ist es nicht abschaltbar.
Nö A.S. Dieser Satz ist nicht der Satz, weswegen ich nach Deiner Meinung 
"ausgerastet" bin.
Das Arrogant bezog sich eher auf den letzten Satz Deines Post's:
A. S. schrieb:
> Ich habe es für Dich klargestellt, weil Du den Thread wohl nur teilweise
> gelesen hast.
Gast #7052364
Lesenswert?

Zeno schrieb:
> Das Arrogant bezog sich eher auf den letzten Satz Deines Post's:
> A. S. schrieb:
>> Ich habe es für Dich klargestellt, weil Du den Thread wohl nur teilweise
>> gelesen hast.

Wenn jemand zentrale Punkte eines Threads nicht erfasst, vermute ich, 
dass er nicht alles gelesen hat. Und nicht:

Zeno schrieb:
> Des Lesens bist Du schon mächtig?
Gast #7052591
Lesenswert?

Wilhelm M. schrieb:
> Was ich meinte, war einfach folgendes.

Du bist komplett auf dem Holzweg und ziehst aus der Arbeitsweise des 
Optimierers falsche Schlüsse.

Wenn Du schon mit Beispielen etwas beweisen willst, musst Du das 
Beispiel auch so konstruieren, damit Du den richtigen Effekt siehst. 
Also z.B. so:
1
extern int a();
2
extern int b();
3

4
void test1() 
5
{
6
  int x = a();
7
  int y = b();
8
  
9
  if (x || y)
10
    puts("test1");
11
}
12

13
void test2()
14
{
15
  if (a() || b())
16
    puts("test2");
17
}

Und wenn Du nun dieses Beispiel kompilierst, siehst Du eben dass der 
Compiler bei test1() immer beide Funktionen, a() und b() exakt 
nacheinander aufruft.

Bei test2() siehst Du, dass der Compiler b() ausschließlich aufruft, 
wenn a() Null zurückgegeben hat. Und das auch völlig unabhängig von der 
verwendeten Optimierungsstufe.

Und das ist per Definition so. Der Operator || macht zwingend eine 
Kurzschlussauswertung. Und bei test1() darf der Compiler auch nicht 
einfach eine Kurzschlussauswertung erfinden, so wie von Dir behauptet.

Bei den bis jetzt hier gezeigten Beispielen kommt der Optimierer nur 
deshalb in die Quere, weil er beweisen konnte, dass manche dieser 
trivialen Beispiel-Funktionen umsortiert oder auch weggelassen werden 
konnten.
Aber genau das hat nichts, aber auch gar nichts mit der 
Kurzschlussauswertung des Operators || zu tun, sondern es waren einfach 
nur untaugliche Beispiele.
#7052639
Lesenswert?

Einer schrieb:
> Du bist komplett auf dem Holzweg und ziehst aus der Arbeitsweise des
> Optimierers falsche Schlüsse.
>
> Wenn Du schon mit Beispielen etwas beweisen willst, musst Du das
> Beispiel auch so konstruieren, damit Du den richtigen Effekt siehst.
> Also z.B. so:
> extern int a();
> extern int b();
> void test1()
> {
>   int x = a();
>   int y = b();
>
>   if (x || y)
>     puts("test1");
> }
> void test2()
> {
>   if (a() || b())
>     puts("test2");
> }

Na, das ist ja ein ganz anderes Beispiel ;-)

Wilhelm M. schrieb:
> Also, die Aussage, dass das Einführen von lokalen Variablen eine
> Auswertung von b() erzwingt ist allgemein falsch. Das funktioniert nur,
> wenn ein sequence-point eingeführt wird. Wie vorher schon geschrieben,
> kann dies geschehen durch
>
> 1) Zugriff auf volatile Objekte,
> 2) Modifikation eines Objektes
> 3) ...
> 4) ... (die Liste ist lang)

Der Compiler muss hier pessimistisch vorgehen, wenn Du ihm komplett die 
Möglichkeit nimmst, zu prüfen, ob ggf. eine Ausnahme aus der o.g. Liste 
zutrifft. Also festzustellen, dass a() oder b() reine Beobachter sind.

Und: ich sage nicht, dass es dasselbe ist wie die Kurzschlussauswertung. 
Ich habe nur gezeigt, dass das Einführen von lokalen Variablen nicht in 
jedem Fall dazu führt, dass bei Funktionen ausgeführt werden. Das war 
mein Einwand. Ja, es ist ein Spezialfall. Doch es hilft eben nicht in 
jedem Fall, lokale Variablen einzuführen. Das ist doch auch klar, 
ansonsten wäre der Optimizer nix.
Gast #7052750
Lesenswert?

Wilhelm M. schrieb:
> Und: ich sage nicht, dass es dasselbe ist wie die Kurzschlussauswertung.

Na, wenn Dich da mal Deine Erinnerung nicht trübt:

Wilhelm M. schrieb:
> Der Compiler wird auch dies bei der Optimierungsstufe > O1 wieder in den
> Code einer Kurzschlussauswertung umwandeln. Es sei denn, man macht die
> temp. Variablen volatile.

Und genau das ist grundlegend falsch.

Der Compiler erfindet eben genau nicht abhängig von der 
Optimierungseinstellung eine Kurzschlussauswertung oder auch nicht.

Du verwechselt Ursache und Wirkung bzw. Du begehst einen klassischem 
Trugschluss:

Wenn aus A auch B folgt, folgt eben genau nicht aus B auch A. Das ist 
falsch. Sondern aus Nicht(B) folgt Nicht(A).

Einfache Logik, aber das bekommen viele nicht auf die Reihe.

"A" bedeutet in diesem Kontext der Quelltext, konkret hier einen 
Kurschluss-Operator, und "B" ist das Kompilat 
(Assemblerlisting/Objektcode).

Du schaust nun auf das Kompilat, erzeugt durch einen Optimierer, und 
schließt dann aus Kompilat "B" auf Quelltext "A". Das ist falsch, das 
geht nicht.
#7052756
Lesenswert?

Einer schrieb:
> Der Compiler erfindet eben genau nicht abhängig von der
> Optimierungseinstellung eine Kurzschlussauswertung oder auch nicht.

Die Aussage war, dass das Einführen von lokalen Variablen für die 
Ergebnisse von a() und b() die Ausführung von a() und b() erzwingt. Ich 
habe oben den Gegenbeweis erbracht. In diesem Fall ist es legitim, ein 
Gegenbeispiel anzuführen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren