Was bedeutet i = (i, ++i, 1) + 1; tun?

Lesezeit: 7 Minuten

Benutzeravatar von gsamaras
Gsamaras

Nachdem ich diese Antwort über undefiniertes Verhalten und Sequenzpunkte gelesen hatte, schrieb ich ein kleines Programm:

#include <stdio.h>

int main(void) {
  int i = 5;
  i = (i, ++i, 1) + 1;
  printf("%d\n", i);
  return 0;
}

Die Ausgabe ist 2. Oh Gott, ich habe das Dekrement nicht kommen sehen! Was passiert hier?

Außerdem erhielt ich beim Kompilieren des obigen Codes eine Warnung mit der Aufschrift:

px.c:5:8: Warnung: linker Operand des Komma-Ausdrucks hat keine Wirkung

  [-Wunused-value]   i = (i, ++i, 1) + 1;
                        ^

Wieso den? Aber wahrscheinlich wird es durch die Beantwortung meiner ersten Frage automatisch beantwortet.

  • Mach keine komischen Sachen, du wirst keine Freunde haben 🙁

    – Marun

    3. Juni 2015 um 8:15 Uhr

  • Die Warnmeldung ist die Antwort auf Ihre erste Frage.

    – Yu Hao

    3. Juni 2015 um 8:17 Uhr

  • @gsamaras: nein. das Ergebnis Wert verworfen wird, nicht die Modifikation. Die eigentliche Antwort: Der Komma-Operator erstellt einen Sequenzpunkt.

    – Karoly Horvath

    3. Juni 2015 um 8:36 Uhr


  • @gsamaras Es sollte dir egal sein, wenn du eine positive Punktzahl hast und noch mehr bei Fragen über 10.

    – Am Himmel liegen

    3. Juni 2015 um 16:43 Uhr

  • Hinweis: Ein optimierender Compiler kann es einfach tun printf("2\n");

    – chux – Wiedereinsetzung von Monica

    3. Juni 2015 um 17:27 Uhr

Benutzeravatar von hackks
hackt

Im Ausdruck (i, ++i, 1)das verwendete Komma ist die Komma-Operator

der Kommaoperator (dargestellt durch das Token ,) ist ein binärer Operator, der seinen ersten Operanden auswertet und das Ergebnis verwirft und dann den zweiten Operanden auswertet und diesen Wert (und Typ) zurückgibt.

Da es seinen ersten Operanden verwirft, ist es im Allgemeinen nur nützlich, wenn der erste Operand wünschenswerte Nebeneffekte hat. Wenn der Nebeneffekt für den ersten Operanden nicht auftritt, generiert der Compiler möglicherweise eine Warnung über den Ausdruck ohne Auswirkung.

Also im obigen Ausdruck ganz links i ausgewertet und sein Wert verworfen. Dann ++i wird ausgewertet und inkrementiert i durch 1 und wieder den Wert des Ausdrucks ++i wird verworfen, aber die nebenwirkung zu i ist dauerhaft. Dann 1 ausgewertet und der Wert des Ausdrucks wird 1.

Es ist äquivalent zu

i;          // Evaluate i and discard its value. This has no effect.
++i;        // Evaluate i and increment it by 1 and discard the value of expression ++i
i = 1 + 1;  

Beachten Sie, dass Der obige Ausdruck ist vollkommen gültig und ruft kein undefiniertes Verhalten auf denn es gibt eine Sequenzpunkt zwischen der Auswertung des linken und rechten Operanden des Kommaoperators.

  • Obwohl der letzte Ausdruck gültig ist, ist der zweite Ausdruck ++i nicht ein undefiniertes Verhalten? es wird ausgewertet und der Wert der nicht initialisierten Variablen wird vorinkrementiert, was nicht richtig ist? oder übersehe ich etwas?

    – Koushik Shetty

    4. Juni 2015 um 5:59 Uhr


  • @Koushik; i wird mit initialisiert 5. Sehen Sie sich die Deklarationserklärung an int i = 5;.

    – Hacken

    4. Juni 2015 um 6:42 Uhr


  • oh mein schlecht. Tut mir leid, dass ich das ehrlich gesagt nicht sehe.

    – Koushik Shetty

    4. Juni 2015 um 6:43 Uhr

  • Hier ist ein Fehler: ++i wird i inkrementieren und dann auswerten, während i++ i auswerten und dann inkrementieren wird.

    – Quentin Hayot

    4. Juni 2015 um 14:54 Uhr

  • @QuentinHayot; Was? Etwaige Nebenwirkungen erfolgt nach der Auswertung der Expression. Im Falle von ++idieser Ausdruck wird ausgewertet, i wird inkrementiert und dieser inkrementierte Wert ist der Wert des Ausdrucks. Im Falle von i++dieser Ausdruck wird ausgewertet, der alte Wert von i wird der Wert des Ausdrucks sein, i wird jederzeit zwischen dem vorherigen und dem nächsten Sequenzpunkt des Ausdrucks inkrementiert.

    – Hacken

    4. Juni 2015 um 16:35 Uhr

Benutzeravatar von Sourav Ghosh
Sourav Ghosh

Zitat von C11Kapitel 6.5.17, Komma-Operator

Der linke Operand eines Kommaoperators wird als void-Ausdruck ausgewertet; es gibt einen Sequenzpunkt zwischen seiner Auswertung und der des rechten Operanden. Dann wird der rechte Operand ausgewertet; das Ergebnis hat seinen Typ und Wert.

Also in deinem Fall

(i, ++i, 1)

wird bewertet als

  1. iwird als void-Ausdruck ausgewertet, Wert verworfen
  2. ++iwird als void-Ausdruck ausgewertet, Wert verworfen
  3. endlich, 1zurückgegebener Wert.

So sieht die letzte Aussage aus

i = 1 + 1;

und i kommt zu 2. Ich denke, das beantwortet beide Fragen,

  • Wie i bekommt einen Wert 2?
  • Warum gibt es eine Warnmeldung?

Hinweis: FWIW, da es eine Sequenzpunkt nach Auswertung des linken Operanden ein Ausdruck wie vorhanden (i, ++i, 1) wird UB nicht als eine aufrufen kann denken im Allgemeinen aus Versehen.

  • +1 Sourav, da dies erklärt, warum die Initialisierung von i hat offensichtlich keine Wirkung! Ich glaube jedoch nicht, dass es für jemanden, der den Kommaoperator nicht kennt, so offensichtlich war (und ich wusste nicht, wie man nach Hilfe sucht, außer eine Frage zu stellen). Schade, dass ich so viele Downvotes bekommen habe! Ich werde die anderen Antworten überprüfen und dann entscheiden, welche ich akzeptiere. Vielen Dank! Schöne Top-Antwort übrigens.

    – Gsamaras

    3. Juni 2015 um 8:22 Uhr


  • Ich glaube, ich muss erklären, warum ich Hacks Antwort akzeptiert habe. Ich war bereit, Ihre zu akzeptieren, da sie wirklich meine beiden Fragen beantwortet. Wenn Sie jedoch die Kommentare zu meiner Frage überprüfen, werden Sie feststellen, dass einige Leute auf den ersten Blick nicht sehen können, warum dies UB nicht aufruft. Hacks-Antworten bieten einige relevante Informationen. Natürlich habe ich die Antwort bezüglich UB in meiner Frage verlinkt, aber einige Leute werden das vielleicht vermissen. Ich hoffe, Sie stimmen meiner Entscheidung zu, wenn nicht, lassen Sie es mich wissen. 🙂

    – Gsamaras

    3. Juni 2015 um 9:12 Uhr

Benutzeravatar von dlask
dunkel

i = (i, ++i, 1) + 1;

Analysieren wir es Schritt für Schritt.

(i,   // is evaluated but ignored, there are other expressions after comma
++i,  // i is updated but the resulting value is ignored too
1)    // this value is finally used
+ 1   // 1 is added to the previous value 1

Also erhalten wir 2. Und jetzt die letzte Aufgabe:

i = 2;

Was auch immer drin war ich bevor es jetzt überschrieben wird.

  • Es wäre schön zu sagen, dass dies wegen des Komma-Operators geschieht. +1 für die Schritt-für-Schritt-Analyse! Schöne Top-Antwort übrigens.

    – Gsamaras

    3. Juni 2015 um 8:30 Uhr


  • Es tut mir leid für die unzureichende Erklärung, ich habe dort nur eine Notiz (…aber ignoriert, es gibt…). Ich wollte hauptsächlich erklären, warum die ++i trägt nicht zum Ergebnis bei.

    – dlask

    3. Juni 2015 um 8:37 Uhr

  • Jetzt werden meine for-Schleifen immer so sein int i = 0; for( ;(++i, i<max); )

    – KaffeeEntwickler

    4. Juni 2015 um 18:36 Uhr


Benutzeravatar von Gopi
Gopi

Das Ergebnis von

(i, ++i, 1)

ist

1

Zum

(i,++i,1) 

die Auswertung erfolgt so, dass die , Der Operator verwirft den ausgewerteten Wert und behält nur den am weitesten rechts liegenden Wert bei 1

So

i = 1 + 1 = 2

Auf der Wiki-Seite für die finden Sie einige gute Lektüre Komma-Operator.

Grundsätzlich ist es

… wertet seinen ersten Operanden aus und verwirft das Ergebnis, wertet dann den zweiten Operanden aus und gibt diesen Wert (und Typ) zurück.

Das bedeutet, dass

(i, i++, 1)

werde das wiederum auswerten iErgebnis verwerfen, auswerten i++verwerfen Sie das Ergebnis, werten Sie es aus und geben Sie es zurück 1.

  • O_O Hölle, ist diese Syntax in C ++ gültig, ich erinnere mich, dass ich einige Stellen hatte, an denen ich diese Syntax brauchte (im Grunde schrieb ich: (void)exp; a= exp2; während ich gerade brauchte a = exp, exp2;)

    – KaffeeEntwickler

    4. Juni 2015 um 18:32 Uhr

Benutzeravatar von Peter Mortensen
Peter Mortensen

Sie müssen wissen, was der Kommaoperator hier tut:

Ihr Ausdruck:

(i, ++i, 1)

Der erste Ausdruck, iwird ausgewertet, der zweite Ausdruck, ++iwird ausgewertet, und der dritte Ausdruck, 1wird für den gesamten Ausdruck zurückgegeben.

Das Ergebnis ist also: i = 1 + 1.

Für Ihre Bonusfrage, wie Sie sehen, der erste Ausdruck i hat überhaupt keine Wirkung, also beschwert sich der Compiler.

  • O_O Hölle, ist diese Syntax in C ++ gültig, ich erinnere mich, dass ich einige Stellen hatte, an denen ich diese Syntax brauchte (im Grunde schrieb ich: (void)exp; a= exp2; während ich gerade brauchte a = exp, exp2;)

    – KaffeeEntwickler

    4. Juni 2015 um 18:32 Uhr

Komma hat einen ‘umgekehrten’ Vorrang. Das erhalten Sie aus alten Büchern und C-Handbüchern von IBM (70er/80er). Der letzte ‘Befehl’ wird also im übergeordneten Ausdruck verwendet.

In modernem C ist seine Verwendung seltsam, aber in altem C (ANSI) sehr interessant:

do { 
    /* bla bla bla, consider conditional flow with several continue's */
} while ( prepAnything(), doSomethingElse(), logic_operation);

Während alle Operationen (Funktionen) von links nach rechts aufgerufen werden, wird nur der letzte Ausdruck als Ergebnis für bedingtes ‘while’ verwendet. Dies verhindert die Handhabung von ‘goto’s, um einen eindeutigen Befehlsblock zu behalten, der vor der Bedingungsprüfung ausgeführt werden soll.

BEARBEITEN: Dies vermeidet auch einen Aufruf einer Behandlungsfunktion, die sich um die gesamte Logik bei linken Operanden kümmern und so das logische Ergebnis zurückgeben könnte. Denken Sie daran, dass wir in der Vergangenheit von C keine Inline-Funktion hatten. Dies könnte also einen Aufruf-Overhead vermeiden.

  • Luciano, Sie haben auch einen Link zu dieser Antwort: stackoverflow.com/questions/17902992/….

    – Gsamaras

    11. Juni 2015 um 13:37 Uhr

  • In den frühen 90er Jahren vor Inline-Funktionen habe ich es häufig verwendet, um Code zu optimieren und zu organisieren.

    – Luciano

    11. Juni 2015 um 13:53 Uhr

1425140cookie-checkWas bedeutet i = (i, ++i, 1) + 1; tun?

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

Privacy policy