In C ++, warum stimmt & amp; & amp; wahr || falsch & amp; & amp; falsch == wahr?
Ich würde gerne wissen, ob jemand weiß, dass der Weg ein compiler interpretieren Sie den folgenden code:
#include <iostream>
using namespace std;
int main() {
cout << (true && true || false && false) << endl; //true
}
Ist dies wahr, da && hat eine höhere Priorität als || oder da || ist ein short-circuit operator (in anderen Worten, ist eine Kurzschluss-Betreiber ignorieren Sie alle nachfolgenden Ausdrücke, oder einfach nur der nächste Ausdruck)?
InformationsquelleAutor der Frage Andrew | 2010-10-31
Du musst angemeldet sein, um einen Kommentar abzugeben.
Caladain hat genau die richtige Antwort, aber ich wollte zu reagieren, zu einem Ihrer Kommentare auf seine Antwort:
Ich denke, ein Teil des Problems ist, dass die Rangfolge nicht ganz meine, was Sie denken, es bedeutet. Es ist wahr, dass
&&
hat eine höhere Priorität als||
und genau diese Konten für das Verhalten, das Sie beobachten. Betrachten wir den Fall mit den gewöhnlichen arithmetischen Operatoren: nehmen wir an, wir habena * b + c * (d + e)
. Was Vorrang erzählt uns, wie Klammern einfügen: ersten um*
dann um+
. Dies gibt uns(a * b) + (c * (d + e))
; in Ihrem Fall, wir haben(1 && 1) || (infiniteLoop() && infiniteLoop())
. Dann stellen Sie sich die Ausdrücke immer Bäume. Um dies zu tun, zu transformieren, für jeden operator in einem Knoten mit zwei Argumente als Kinder:Auswertung dieser Baum ist, wo Kurzschluss kommt. In der arithmetischen Struktur, Sie können sich vorstellen, eine Breite-zuerst bottom-up-Ausführung style: zuerst bewerten
DE = d + e
dannAB = a * b
undCDE = c * DE
und das Ergebnis istAB + CDE
. Aber beachten Sie, dass Sie ebenso gut bewertetAB
zuerst, dannDE
CDE
und das endgültige Ergebnis; Sie können nicht sagen, der Unterschied. Da jedoch||
und&&
sind, kurzzuschließen, Sie haben Verwendung dieser leftmost-erste Bewertung. So, zur Bewertung der||
wir zuerst bewerten1 && 1
. Da dies wahr ist,||
Kurzschlüsse und ignoriert seine rechten hand Zweig—obwohl wenn es hatte ausgewertet, er hätte ausgewertet, dieinfiniteLoop() && infiniteLoop()
ersten.Wenn es hilft, können Sie denken, dass jeder Knoten in dem Baum als eine Funktion aufrufen, erzeugt die folgende Darstellung
plus(times(a,b), times(c,plus(d,e)))
im ersten Fall, undor(and(1,1), and(infiniteLoop(),infiniteLoop())
im zweiten Fall. Kurzschluss bedeutet, dass Sie vollständig bewerten jede linke-hand-Funktion argumentor
oderand
; wenn estrue
(füror
) oderfalse
(fürand
), dann ignorieren Sie die Rechte-hand-argument.Ihren Kommentar setzt Voraus, dass wir bewerten alles mit der höchsten Priorität zuerst, dann alles mit der nächsten höchsten Rang, und so weiter und so Fort, das entspricht einer Breite-zuerst bottom-up-Ausführung von dem Baum. Stattdessen, was passiert ist, dass die Rangfolge sagt uns, wie Sie bauen den Baum. Die Regeln für die Ausführung des Baumes irrelevant für die einfachen arithmetischen Fall; Kurzschluss, jedoch ist gerade eine genaue Angabe wie bewerten Sie den Baum.
Edit 1: In einem Ihrer anderen Kommentare, Sie sagte
Ja, das ist das, was definiert Vorrang—außer, dass es nicht ganz richtig. Es ist sicherlich ganz richtig in Csondern überlegen Sie, wie würden Sie bewerten den (nicht C!) Ausdruck
0 * 5 ^ 7
im Kopf, wo5 ^ 7 = 57
und^
hat eine höhere Priorität als*
. Entsprechend Ihrer Breite-zuerst bottom-up-Regel, die wir brauchen, um zu bewerten0
und5 ^ 7
bevor wir das Ergebnis finden. Aber Sie würden sich nicht die Mühe zu bewerten5 ^ 7
; Sie würden einfach sagen "gut, da0 * x = 0
für allex
ist, muss diese0
", und überspringen Sie den ganz rechten Zweig. In anderen Worten, ich habe nicht bewertet, beide Seiten vollständig aus, bevor Sie die Auswertung der letzten Multiplikation; ich habe kurzgeschlossen. Ebenso, dafalse && _ == false
undtrue || _ == true
für alle_
können wir nicht berühren der rechten Seite; dies ist, was es bedeutet, wenn ein operator, Kurzschluss. C keine Kurzschluss-Multiplikation (obwohl eine Sprache, die dies tun könnte), aber es hat Kurzschluss&&
und||
.Nur als Kurzschluss
0 * 5 ^ 7
ändert nichts an der üblichen PEMDAS Vorrang Regeln, durch kurzschließen der logischen Operatoren ändert nichts an der Tatsache, dass&&
hat eine höhere Priorität als||
. Es ist einfach eine Abkürzung. Da wir zu wählen haben einige Seite der Betreiber zu bewerten erste -, C-verspricht auswerten der linken Seite des logischen Operatoren zuerst; sobald es fertig ist, gibt es eine offensichtliche (und nützliche) Weise zu vermeiden auswerten der rechten Seite für bestimmte Werte, und C verspricht, dies zu tun.Ihre Regel—auswerten des Ausdrucks zuerst der Breite bottom-up—ist auch gut definiert, und eine Sprache auswählen konnte, dies zu tun. Allerdings hat es den Nachteil nicht erlaubt Kurzschluss, das ist ein sinnvolles Verhalten. Aber wenn jeder Ausdruck in Ihrem Baum ist gut definiert (keine Schleifen) und rein (nicht ändern von Variablen, Druck, etc.), dann kann man nicht sagen, der Unterschied. Es ist nur in diesen seltsamen Fällen, die die mathematischen Definitionen von "und" und "oder" don ' T cover, das den Kurzschluss ist noch sichtbar.
Beachten Sie auch, dass es nichts grundlegende über die Tatsache, dass durch kurzschließen arbeiten durch die Priorisierung der linke Ausdruck. Könnte man definiert eine Sprache, Ɔ, wo
⅋⅋
stelltand
und\\
stellt||
aber wo0 ⅋⅋ infiniteLoop()
und1 \\ infiniteLoop()
würde-Schleife und dieinfiniteLoop() ⅋⅋ 0
undinfiniteLoop() \\ 1
wäre false und true. Diese gerade entspricht der Wahl zum auswerten der rechten Seite zuerst anstelle von der linken Seite, und dann die Vereinfachung auf die gleiche Weise.In einer nussschale: was Vorrang erzählt uns wie Sie zum Aufbau des parse-Baum. Die einzig sinnvolle Aufträge für die Evaluierung des parse-tree sind diejenigen, die sich Verhalten als wenn bewerten wir es zuerst der Breite bottom-up (wie Sie wollen) auf gut definierten reinen Werte. Für Undefinierte oder unreine Werte einige lineare Ordnung, muss gewählt werden.1 Einmal eine lineare Ordnung gewählt ist, werden bestimmte Werte für eine Seite die ein Betreiber möglicherweise eindeutig zu bestimmen das Ergebnis des gesamten Ausdrucks (z.B.
0 * _ == _ * 0 == 0
false && _ == _ && false == false
odertrue || _ == _ || true == true
). Aufgrund dieser, Sie können in der Lage sein, um Weg zu bekommen ohne die Durchführung der evaluation von was auch immer danach kommt in der linearen Reihenfolge; C verspricht, dies zu tun für die logischen Operatoren&&
und||
durch die Auswertung diese in einer von-Links-nach-rechts-Mode, und nicht für irgendetwas anderes. Jedoch, Dank der Vorrang, wir tun wissen, dasstrue || true && false
isttrue
und nichtfalse
: weilstatt
1: Eigentlich könnten wir theoretisch auch auswerten beiden Seiten eines operators in parallelen, aber das ist nicht wichtig, jetzt, und sicherlich würde keinen Sinn machen für C. Dies führt zu flexibleren Semantik, aber eine, die hat Probleme mit Nebenwirkungen, wenn Sie tun, Sie passieren?).
InformationsquelleAutor der Antwort Antal Spector-Zabusky
&&
hat eine höhere Priorität als||
.InformationsquelleAutor der Antwort AngelLeliel
(true && true || false && falsch) ausgewertet wird, mit && haben eine höhere Priorität.
Update:
Warum diese produzieren true in C++?
Wie vor, können es zu brechen auseinander. && hat eine höhere Priorität gibt, | | und Boolesche Aussagen Kurzschluss in C++.
Wenn ein bool-Wert konvertiert einen integer-Wert, dann
Ergibt der Ausdruck dieses (true) && (wahre) Aussage, die Kurzschluss ||, die verhindert, dass die Endlosschleifen laufen. Es gibt eine Menge mehr compiler-Juju geht, so ist dies eine vereinfachende Sicht der situation, die angemessen ist für dieses Beispiel.
In einem NICHT-kurzgeschlossen Umgebung, Dass die expression würde immer hängen, da beide Seiten der ODER sein würden "ausgewertet" und auf der rechten Seite hängen würde.
Wenn Sie verwirrt sind über den Vorrang, so würde die Dinge bewerten, die in Ihrer ursprünglichen post, wenn || hatte höhere Priorität als &&:
Ich kann mich nicht erinnern, wenn es geht von rechts nach Links, oder von Links nach rechts, aber das Ergebnis wäre das gleiche. In Ihrem zweiten Beitrag, wenn || hatte höhere precendence:
tl;dr: Es ist immer noch Vorrang, dass die &&'s zuerst ausgewertet werden, aber der compiler Kurzschluss ODER so. Im wesentlichen werden die compiler-Gruppen die Reihenfolge der Operationen wie diese (VEREINFACHENDE SICHT, setzen unten die Mistgabeln :-P)
Update #2:
"Allerdings, dieses Beispiel beweist && NICHT Vorrang haben, als der || wird ausgewertet, bevor die zweite &&. Dies zeigt, dass && und || haben die gleiche Priorität und werden ausgewertet, in der von-Links-nach-rechts-Ordnung".
"Wenn && hatte Vorrang, es würde bewerten die erste && (1), dann die zweite && (Endlosschleifen) und hängen Sie das Programm. Da dies nicht geschehen ist, && wird nicht ausgewertet, bevor Sie auf ||."
Let ' s decken Sie diese im detail.
Wir reden über zwei verschiedene Dinge hier. Rangfolge, die bestimmt die Reihenfolge der Operationen, und kurzschließen, was ein compiler/Sprache trick zum speichern von Prozessor-Zyklen.
Let ' s cover Priorität zuerst. Vorrang ist die Abkürzung für "Order of Operations" Im wesentlichen, angesichts dieser Aussage:
1 + 2 * 3
in welcher Reihenfolge sollen die Operationen gruppiert werden, die für die evaluation?
Mathematik klar definiert die Reihenfolge der Operationen geben die Multiplikation höhere Priorität hat als die addition.
Jetzt, können den übergang in die Boolesche Ausdrücke (&& = UND, || = ODER)
C++ haben UND eine höhere Priorität als or, somit
So, nur auf Vorrang, (true && true || false && false) betrieben werden-in dieser Reihenfolge:
Mit mir so weit? Kommen wir nun in ein Kurzschluss:
In C++ Boolesche Aussagen sind, was heißt "kurzgeschlossen". Dies bedeutet, dass der compiler Blick auf eine gegebene Anweisung wählen Sie die "besten Weg" für die Bewertung. Nehmen Sie dieses Beispiel:
Wie Sie sehen können, wenn (true && wahr) ausgewertet wird, WAHR ist, dann es gibt keine Notwendigkeit, verbringen die clock-Zyklen auswerten if (false && falsch)) wahr ist.
C++ Immer kurz Circuts, aber auch andere Sprachen bieten Mechanismen für sogenannte "Begierig" - Betreiber.
Nehmen Sie zum Beispiel die Programmiersprache Ada. In Ada, "UND" und "ODER" sind "Begierig" Betreiber..Sie zwingen, alles zu bewerten.
In Ada (wahr UND wahr) ODER (falsch UND falsch) wäre zu evaluieren (true UND true) und (false, UND false) bevor die Bewertung der ODER. Ada gibt Ihnen Auch die Möglichkeit zum Kurzschluss UND DANN und ODER ANDERES, was Ihnen das gleiche Verhalten von C++ tut.
Ich hoffe, dass vollständig beantwortet Ihre Frage. Wenn nicht, lass es mich wissen 🙂
Update 3: Letzten update, und dann werde ich weiter auf E-Mail, wenn Sie immer noch Probleme.
"Wenn Kurzschluss der | | - operator Auftritt, und Kurzschlüsse die Ausführung des zweiten && Ausdruck, der bedeutet, dass der | | - operator ausgeführt wurde, BEVOR die zweite && - operator. Dies impliziert, Links-nach-rechts-Ausführung für && und || (nicht && Vorrang)."
Schauen wir uns dann in diesem Beispiel:
Wenn das, was Sie sagten, wahr war, InfLoop bekommen würde, trifft in den ersten beiden.
Sie werden auch bemerken, InfLoop() nicht aufgerufen werden, im Dritten Beispiel.
Nun, betrachten Sie dieses:
Infloop aufgerufen wird! Wenn ODER hatte eine höhere precendence als &&, dann würde der compiler auswerten:
Aber InfLoop aufgerufen wird! Dies ist der Grund, warum:
Precendece stellt NUR die Gruppierung von Operationen. In diesem, && ist größer als ||.
Den Compiler Dann kommt und bestimmt, was, um es ausführen sollte die Bewertung zu geben, es die beste chance für das speichern von Zyklen.
Es ist kindof eine Tatsache..und ich weiß nicht, wie sonst, um dies zu demonstrieren. Rangfolge wird bestimmt durch die Sprache, die Grammatik-Regeln. Die Compiler-Optimierung wird ermittelt, indem jedem compiler..einige sind besser als andere, aber Alle sind frei, um die Reihenfolge der gruppierten Vergleiche, wie es gerade passt, damit es die "beste" chance für die Schnellste Ausführung mit den wenigsten Vergleiche.
InformationsquelleAutor der Antwort Caladain
Zwei Tatsachen erklären, das Verhalten der beiden Beispiele. Erstens, den Vorrang der
&&
höher ist als||
. Zweitens, die sowohl logische Operatoren mit short-circuit-evaluation.Rangfolge wird oft verwechselt mit der Reihenfolge der Bewertung, aber es ist unabhängig. Ein Ausdruck kann für die einzelnen Elemente ausgewertet, in beliebiger Reihenfolge, solange das Endergebnis korrekt ist. Im Allgemeinen für einige Betreiber, was bedeutet, dass der Wert auf der linken Seite (LHS), die ausgewertet werden kann, entweder bevor oder nachdem der Wert auf der rechten Seite (RHS), solange beide werden ausgewertet, bevor der operator selbst angewendet wird.
Den logischen Operatoren haben eine spezielle Eigenschaft: in bestimmten Fällen, wenn von einer Seite ausgewertet, um einen bestimmten Wert, dann wird der Betreiber den Wert bekannt ist, unabhängig von dem Wert, auf der anderen Seite. Um diese Eigenschaft nützlich ist, die Sprache C (und durch Erweiterung, jede C-ähnliche Sprache) angegeben hat, die mit logischen Operatoren zu bewerten, die LHS vor der RHS, und weiter, bis nur bewerten die RS, wenn sein Wert erforderlich zu wissen, das Ergebnis des operators.
So, vorausgesetzt, die üblichen Definitionen von
TRUE
undFALSE
TRUE && TRUE || FALSE && FALSE
ausgewertet, beginnend an der linken Seite. Die erstenTRUE
nicht zwingen, das Ergebnis der ersten&&
also der zweiteTRUE
ausgewertet wird, und dann der AusdruckTRUE && TRUE
ausgewertet wird (TRUE). Nun, die||
kennt die LS. Noch besser, seine LHS gezwungen hat, das Ergebnis der||
bekannt sein, so springt die Auswertung der gesamten RS.Die exakt gleiche Reihenfolge der Auswertung gilt für den zweiten Fall. Da die RHS der
||
ist irrelevant, es wird nicht ausgewertet und weder AufrufinfiniteLoop()
gemacht wird.Dieses Verhalten ist beabsichtigt und sinnvoll ist. Zum Beispiel können Sie schreiben
p && p->next
zu wissen, dass der Ausdruck nie versuchen dereference einen NULL-Zeiger.InformationsquelleAutor der Antwort RBerteig
&&
hat in der Tat eine in der Rangfolge höher steht.InformationsquelleAutor der Antwort Ignacio Vazquez-Abrams
Nicht ganz.
Bewertet werden möchte wie dieser:
xx && yy
||
und der erste Teil der Aussage wahr ist, überspringen Sie den rest.||
und bewerten Sie:zz && qq
||
.Aus meinem Verständnis, C++ ist so konzipiert, dass er liest Dinge, bevor es beginnt die Auswertung. Nach allem, in unserem Beispiel, die es nicht wissen, dass wir eine zweite
&&
- check nach||
bis er es liest, Bedeutung es hat, Lesen Sie in der||
bevor es auf die zweite&&
. Als solche, wenn der erste Teil wahr ausgewertet, es wird nicht der Teil nach dem||
aber wenn der erste Teil false ergibt, dann Mach es den ersten Teil, Lesen Sie in der||
finden und bewerten der zweite Teil, und verwenden Sie das zweite Teil ist das Ergebnis zur Bestimmung des endgültigen Ergebnis.InformationsquelleAutor der Antwort Anonymoose
bezüglich deines edit: infiniteLoop() nicht ausgewertet, da true || (was auch immer) ist immer wahr. Verwenden Sie true, | (was auch immer) wenn was ausgeführt werden soll.
InformationsquelleAutor der Antwort Philipp
über die
true && true || infiniteLoop() && infiniteLoop()
Beispiel, weder für die endlos-Schleife ruft bewertet wird, wegen der zwei Eigenschaften kombiniert: && hat Vorrang vor | | und || Kurzschlüsse, wenn die linke Seite wahr ist.wenn && und || hatte das gleiche Rangfolge, die Bewertung müsste so gehen:
aber, da &&'s Rangfolge, die Bewertung geht eigentlich
InformationsquelleAutor der Antwort filipe
Bezug auf Andrew ' s neuesten code,
Short-circuit-evaluation bedeutet, dass die Aufrufe
infiniteLoop
garantiert nicht ausgeführt werden.Aber, es ist interessant, auf eine perverse Art und Weise, da die C++0x draft macht der infinite-loop-das-tut-nichts Undefiniertes Verhalten. Dass die neue Regel gilt allgemein als sehr unerwünscht und dumme, geradezu gefährlich, aber irgendwie schlich in den Entwurf. Teilweise aus Gründen der threading-Szenarien, wo der Autor von einem Papier dachte, es würde eine Vereinfachung der Regeln für etwas-oder-andere ziemlich irrelevant.
So, mit einem compiler, der auf der "leading edge" der C++0x-Konformität das Programm beenden konnte, mit einige Folge, auch wenn es ausgeführt, ein Aufruf
infiniteLoop
! Natürlich, mit einem solchen compiler könnte es auch produzieren, die gefürchteten Phänomen, Nasen-daemons...Glücklich, wie bereits erwähnt, short-circuit-evaluation bedeutet, dass die Anrufe garantiert nicht ausgeführt werden.
Cheers & hth.,
InformationsquelleAutor der Antwort Cheers and hth. - Alf
Da und/oder/true/false ist sehr ähnlich */+/1/0 (Sie sind mathematisch gleichwertig-ish), ist das folgende auch true:
sind und eher leicht zu merken...
Also ja, es hat zu tun mit Vorrang und Kurzschluss. Precendence von boolean ops ist ziemlich einfach, wenn Sie ordnen Sie es den entsprechenden integer-ops.
InformationsquelleAutor der Antwort Macke
Dies ist eine fortlaufende illustration:
aber auch beachten, dass, wenn es ist
dann die Rechte Seite nicht ausgewertet, so dass jede Funktion gibt es nicht, und der Ausdruck wird nur zurück
true
.InformationsquelleAutor der Antwort 太極者無極而生
Ist die einfache Antwort, && nimmt eine höhere Priorität als | | hat. Zudem wird der code nicht ausgeführt, da braucht er nicht zu sein, zu wissen, das Ergebnis des booleschen Ausdrucks. Ja, es ist eine compiler-Optimierung.
InformationsquelleAutor der Antwort Carl