Warum ist “if (i++ && (i == 1))” falsch, wobei i ein int mit dem Wert 1 ist?

Lesezeit: 8 Minuten

Benutzeravatar von Tahir Sanglikar
Tahir Sanglikar

{
    int i = 1;
    if (i++ && (i == 1))
        printf("Yes\n");
    else
        printf("No\n");
}

Nach meinem Verständnis in der if Bedingung, zuerst der Ausdruck (i==1) wird ausgewertet, was zurückgegeben werden sollte 1und dann wird logischerweise mit anded 1 das ist der Wert von ialso sollte der Ausdruck zurückkehren 1 && 1 == 1aber die else Teil ausgeführt wird.

Kann mir bitte jemand erklären, warum die else Teil ausgeführt?

  • Nicht das Problem, aber Sie brauchen keine Klammern i == 1.

    – Peter Becker

    12. Juli 2015 um 12:52 Uhr

  • Es sieht so aus, als würden Sie erwarten i == 1 zuerst ausgewertet werden, weil Sie eine gewisse Erwartung haben, dass Dinge in Klammern zuerst passieren. Sie tun es nicht; Klammern haben nichts mit der Auswertungsreihenfolge zu tun. Sie steuern nur die Gruppierung von Argumenten.

    – Benutzer2357112

    12. Juli 2015 um 14:45 Uhr

  • @Pete Becker: Ja, das tun Sie, um dem Leser Ihre Absicht klar zu machen – und um sicherzustellen, dass der Compiler das tut, was Sie wirklich beabsichtigt haben. Nicht, dass es in diesem Fall wirklich zutrifft: Wenn sich dieser Schnipsel im tatsächlichen Produktionscode befindet, sollte der Autor nie wieder arbeiten.

    – jamesqf

    12. Juli 2015 um 17:09 Uhr

  • Ein wenig verwandt: Sie können auch ein einzelnes kaufmännisches Und verwenden (&). Es wird das erste Argument prüfen, und wenn ja false (oder fälschlicherweise), wird die Überprüfung der nächsten Argumente übersprungen, da das gesamte Argument bereits vorhanden ist false.

    – Gideon

    13. Juli 2015 um 9:53 Uhr

  • @ Gideon Verwenden & statt && erzwingt nicht, dass die linke Seite des Operanden zuerst ausgewertet wird: der Sequenzpunkt existiert nicht mit & zwischen den beiden Seiten. Mit &, könnte die rechte Seite zuerst auswerten. OP hat Recht mit der Frage &&. Mit & es ist undefiniertes Verhalten. Siehe Antwort

    – chux – Wiedereinsetzung von Monica

    14. Juli 2015 um 21:08 Uhr

Benutzeravatar von Jonathan Leffler
Jonathan Leffler

Nein. In C gibt es a Sequenzpunkt zwischen der Auswertung der LHS der && Bediener und die Bewertung des RHS, und die Erhöhung muss stattfinden und abgeschlossen sein, bevor der RHS bewertet wird. Also, die i++ (gleichwertig i++ != 0) ausgeführt und das Inkrement abgeschlossen ist (und der Ausdruck als wahr ausgewertet wird), sodass zum Zeitpunkt der Auswertung von RHS i == 2 und daher ist der Gesamtausdruck falsch und es wird „Nein“ ausgegeben. Wenn die LHS des && Operator als falsch (0) ausgewertet, würde die RHS wegen der „Kurzschluss“-Eigenschaft von nicht ausgewertet && Operator.

Nur wenige Operatoren haben die Eigenschaft, einen Sequenzpunkt zwischen der Auswertung von LHS und RHS zu haben: &&, ||und , (als Operator, nicht als Trennzeichen in einer Argumentliste) – und da ist ? : auch, der kein binärer Operator ist, aber einen Sequenzpunkt hat, nachdem die Bedingung ausgewertet wurde und vor dem Ausdruck nach dem ? oder der Ausdruck nach dem : ausgewertet wird (von denen immer das eine oder das andere, aber nicht beide ausgewertet wird).

Das && und || Operatoren sind die einzigen Operatoren mit der Eigenschaft „Kurzschluss“. Die RHS von && wird nur ausgewertet, wenn LHS wahr ergibt; die RHS von || wird nur ausgewertet, wenn die LHS als falsch ausgewertet wird.


Klarstellung zu Sequenzpunkten

Iwillnotexist Idonotexist korrekt behauptet:

Der C11-Standard hat Sequenzpunkte nicht abgeschafft, nur der C++11-Standard hat dies getan.

C++11 (ISO/IEC 14882:2011) sagt:

1.9 Programmausführung

¶13 Vorher sequenziert ist eine asymmetrische, transitive, paarweise Beziehung zwischen Bewertungen, die von einem einzelnen Thread (1.10) ausgeführt werden, was eine teilweise Ordnung zwischen diesen Bewertungen induziert. Gegeben zwei Auswertungen EIN und Bwenn
EIN vorher sequenziert ist Bdann die Ausführung von EIN geht der Vollstreckung voraus B. Wenn EIN ist vorher nicht sequenziert
B und B ist vorher nicht sequenziert EINdann EIN und B sind unsequenziert. [Note: The execution of unsequenced
evaluations can overlap. —end note] Auswertungen EIN und B sind unbestimmt geordnet wann auch immer EIN
vorher sequenziert ist B oder B vorher sequenziert ist EINaber es ist nicht angegeben, welche. [Note: Indeterminately
sequenced evaluations cannot overlap, but either could be executed first. —end note]

Der Begriff „Sequenzpunkt“ kommt in C++11 überhaupt nicht vor (die einzige nahe Übereinstimmung ist „Sequenzzeiger“).

C11 (ISO/IEC 9899:2011) sagt:

5.1.2.3 Programmausführung

¶3 Vorher sequenziert ist eine asymmetrische, transitive, paarweise Beziehung zwischen Bewertungen, die von einem einzelnen Thread ausgeführt werden, was eine teilweise Ordnung zwischen diesen Bewertungen induziert. Gegeben zwei Auswertungen EIN und Bwenn EIN vorher sequenziert ist Bdann die Ausführung von EIN
geht der Vollstreckung voraus B. (Umgekehrt, wenn EIN vorher sequenziert ist Bdann B ist
sequenziert nach EIN.) Wenn EIN ist nicht vorher oder nachher sequenziert Bdann EIN und B sind
unsequenziert. Auswertungen EIN und B sind unbestimmt geordnet Wenn EIN wird entweder davor oder danach sequenziert Baber es ist nicht angegeben, welche.13) Das Vorhandensein eines Sequenzpunkt
zwischen der Auswertung von Ausdrücken EIN und B impliziert, dass jeder Wert mit Berechnung und Nebeneffekt verbunden ist EIN wird vor jeder Wertberechnung und damit verbundenen Nebenwirkung sequenziert B. (Eine Zusammenfassung der Sequenzpunkte befindet sich in Anhang C.)

13) Die Ausführungen von Auswertungen ohne Sequenz können verschachtelt werden. Unbestimmt aufeinanderfolgende Auswertungen können nicht verschachtelt, aber in beliebiger Reihenfolge ausgeführt werden.

C11 behält also Sequenzpunkte bei, fügt jedoch das „sequenced before“ und verwandte Begriffe hinzu, wobei im Wesentlichen dieselbe Terminologie wie in C++11 verwendet wird.

  • Perfekt. if ((i == 1) && i++ ) gedruckt hätte Yes.

    – Bhargav Rao

    12. Juli 2015 um 3:34 Uhr

  • @JonathanLeffler: Danke, dass du dich mit qualifiziert hast was früher als Sequenzpunkt bezeichnet wurde. Ich wusste nicht, dass die Terminologie in C++11 geändert und erweitert wurde (vgl Wikipedia).

    – Rusty Shackleford

    12. Juli 2015 um 3:44 Uhr

  • @Equality7-2521: Die Terminologie „sequenziert vor“, „sequenziert nach“, „unbestimmt sequenziert“ und „nicht sequenziert“ gilt auch für C11. Ich glaube, die neue Terminologie wurde zum Teil eingeführt, weil in beiden Standards Threading-Unterstützung hinzugefügt wurde.

    – Jonathan Leffler

    12. Juli 2015 um 3:50 Uhr

  • @JonathanLeffler: (Randnotiz) Wenn ich mich richtig erinnere, Sequenzpunkt für ?: wird nur einmal garantiert, das heißt unmittelbar nach Auswertung seines ersten Operanden (dh Bedingung) und sonst nichts.

    – Grzegorz Szpetkowski

    12. Juli 2015 um 8:45 Uhr


  • @JonathanLeffler Der C11-Standard hat die Sequenzpunkte nicht abgeschafft, nur der C++ 11-Standard (aus welchem ​​Grund auch immer). §6.5.13p4: Im Gegensatz zur bitweisen Binärdatei & Betreiber, der && Operator garantiert Links-nach-Rechts-Auswertung; wenn der zweite Operand ausgewertet wird, gibt es a Sequenzpunkt zwischen den Auswertungen des ersten und zweiten Operanden. Wenn der erste Operand gleich 0 ist, wird der zweite Operand nicht ausgewertet. (Betonung hinzugefügt)

    – Ich werde nicht existieren Ich werde nicht existieren

    12. Juli 2015 um 13:45 Uhr

Benutzeravatar von Sruit A.Suk
Sruit A.Suk

Hier eine einfache Erklärung

Geben Sie hier die Bildbeschreibung ein

und deshalb wird diese Bedingung ‘falsch’

  • Abgesehen von vorhandenen Antworten wurde nichts Neues hinzugefügt, daher eine Ablehnung!

    – Bin_ich_hilfreich

    12. Juli 2015 um 18:44 Uhr

  • @shekharsuman Nein, ich selbst fand diese Antwort am klarsten, es sei denn, Sie möchten dieses Konzept natürlich formal verstehen.

    Benutzer2953119

    12. Juli 2015 um 19:57 Uhr

  • Sauber und einfach, aber es erklärt nicht, warum der Ausdruck in der Klammer nicht zuerst ausgeführt wurde.

    – Derek 朕會功夫

    12. Juli 2015 um 22:44 Uhr


  • Dies sagt, was passiert, erklärt aber nicht, warum. Zum Beispiel der Code if (i++ & (i == 1)) [...] (beachten Sie das einzelne kaufmännische Und) würde zu unterschiedlichen Ergebnissen führen, aber Ihre Antwort erwähnt keines der Konzepte, die jemandem helfen würden, herauszufinden, warum.

    – David Richerby

    13. Juli 2015 um 1:31 Uhr


  • Eigentlich denke ich, dass es einfach genug ist. Es erklärt das Verhalten durch das Diagramm. Es ist vollkommen in Ordnung für mich.

    – Zizouz212

    13. Juli 2015 um 3:22 Uhr

Wann && in einem Ausdruck verwendet wird, sind seine Argumente garantiert von links nach rechts ausgewertet. So i wird den Wert von haben 2 Wenn (i==1) ausgewertet wird. Daher ist der Ausdruck falsch, und die else Teil wird ausgeführt.

Beachten Sie jedoch der Vollständigkeit halber, dass das rechte Argument überhaupt nicht ausgewertet wird, wenn das linke Argument als falsch oder 0 ausgewertet wird.

  • Keine ganz klare Formulierung. Was bedeutet “garantiert von links nach rechts ausgewertet werden”, wenn das zweite Argument nicht einmal garantiert überhaupt ausgewertet wird? (Das bedeutet, dass, wenn das zweite Argument überhaupt ausgewertet wird, dies erfolgt, nachdem die Auswertung des ersten Arguments, einschließlich aller Nebeneffekte, abgeschlossen ist; das hätten Sie also sagen sollen.)

    – Marc van Leeuwen

    12. Juli 2015 um 19:51 Uhr

  • In diesem Zusammenhang bedeutet die Garantie, dass die Klammern nicht zuerst ausgewertet werden, ziemlich klar für mich. +1 für die einfache Erklärung von @MichaelL, obwohl die Diskussion der Sequenzpunkte für das Verständnis von zentraler Bedeutung ist.

    – Strattonn

    13. Juli 2015 um 10:18 Uhr

Benutzeravatar von Codecracker
Codeknacker

Ich denke 1&&1=1 und 1&&0=0 ist dir klar. Die Antwort von Michael L scheint mir gut zu sein. Aber ich werde trotzdem versuchen, ein wenig näher darauf einzugehen. Hier ist ein Link, der eine Operator-Prioritätsliste bereitstellt:

http://www.difranco.net/compsci/C_Operator_Precedence_Table.htm

Wenn Sie diesen Link besuchen und auf diese Tabelle verweisen, werden Sie feststellen, dass && eine Links-Rechts-Assoziativität aufweist. Also wird zuerst i zu 2 NACH dem linken Teil (Sruit hat versucht, dies anhand des Diagramms zu zeigen); dann für den rechten Teil i== 1 Überprüfung ist abgeschlossen. Wir können dies überprüfen, indem wir den Code wie den unten angegebenen schreiben:

Dieser Code erklärt, dass i=2 ist, wenn der Ausführungsfluss den Teil i==1 erreicht.

#include <stdio.h>
int main() {
    
    int i = 1;
    if (i++ && (printf("%d\n",i)))
        printf("Yes\n");
    else
        printf("No\n");
    return 0;
}

Die Ausgabe ist also:

2

Ja

Also stellt sich heraus, dass 2==1 falsch ist und letztendlich gibt die Antwort ein überraschendes Gefühl!!! Die rechte Klammer ergibt 0 und die linke Seite 1, also 1&&0=0. Ich denke, das ist fair genug, um es zu verstehen.

Benutzeravatar von Muhammad Nasir
Muhammad Nassir

Sie sind verwirrt, weil in Loop-Anweisung i++ wird für das Post-Inkrement verwendet. z.B

for (i=0;i<1;i++)

Im obigen Schleifenprogramm i wird zuerst den Anfangswert erhalten und den Zustand prüfen. Das if Bedingung ist wahr, also erhöht sie sich ich und bewertet ich auf den alten Wert für den Schleifenkörper, aber außerhalb des Schleifenkörpers hat es einen neuen Wert 1.

In Ihrer Frage verwenden Sie if und Umfang des alten Wertes von i endet, wenn es auf einen logischen Operator stößt, erhält es automatisch einen neuen Wert und erhöht es 2 die Bedingung gibt also false zurück.

1406370cookie-checkWarum ist “if (i++ && (i == 1))” falsch, wobei i ein int mit dem Wert 1 ist?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy