2017-05-27 5 views
2

Okay, ich kenne die Ausgabe für den Ausdruck (x * = y = z = 4;) ist 40; aber wie genau haben wir 40 bekommen? Können Sie mir bitte Schritt für Schritt zeigen?Lösen von zusammengesetzten Zuweisungsausdrücken

dachte ich, der Vorrang von rechts ist so nach links (2 * 4) = (z = 4), verstehe ich nicht

#include <stdio.h> 
#define PRINTX printf("%d\n",x) 

int main (void){ 
    int x = 2, y, z; 
    x *= 3 + 2; 
    PRINTX; 
    x *= y = z = 4; 
    PRINTX; 
    x = y == z; 
    PRINTX; 
    x == (y = z); 
    PRINTX; 
    return 0; 
} 
+0

Gute Frage übrigens. – EJoshuaS

Antwort

4

Nein, der einzige Weg, dass Zuordnung hier ausgewertet werden kann, ist rechts nach links.

Beachten Sie zuerst, dass x *= 99 zum Beispiel eine Kurzschrift für x = x * 99 ist.

Mit dieser sagte,

x *= y = z = 4; 

äquivalent zu

z = 4; 
y = z; 
x *= y; // This is shorthand for x = x * 4 

Überlegen Sie, was passiert, wenn man versucht, es umgekehrt zu bewerten:

// y is unininitialized 
x *= y; 
y = z; 
z = 4; 

Es würde scheitern .

Also wirklich,

// x = 2 
int x = 2, y, z; 
// x = x * (3 + 2) = x * 5 = 2 * 5 = 10 
x *= 3 + 2; 

// x = x * 4 = 10 * 4 = 40 
x *= y = z = 4; 

Dies kann als

int x, y, z; 
x = 2; // x = 2 
x = x * (3 + 2); // This is 2 * 5, so x = 10 after this 

z = 4; // z = 4 
y = z; // y = 4 
x = x * y; // x = 10 * 4 = 40 

neu geschrieben werden, und das ist, wie Sie mit 40

+0

Danke, aber ich bin sehr verwirrt. Wo hast du die 5 her? Ich dachte, es sei x * 4 und wo ist x * = 3 * 2; komm von – nonameisbetter

+0

@nonameisbetter ich aktualisiert. Die '5' kommt von' 3 + 2'. 'x * = 3 + 2' ist äquivalent zu 'x * = (3 + 2)', was äquivalent zu 'x * = 5' ist. – EJoshuaS

2

am Ende Sie haben:

int x = 2, y, z; 
x *= 3 + 2; 

Diese ist eine Abkürzung für x = x * (3 + 2), die 10 ergibt, vorausgesetzt, dass x bei 2 beginnt.

PRINTX; 
x *= y = z = 4; 

Nach diesem y == z und beide werden auf 4; und x ist das 4-fache seines vorherigen Wertes von 10, daher 40.

PRINTX; 
x = y == z; 

Dieser vergleicht y und z; sie sind gleich, so wird x1 zugewiesen (Vergleiche immer 0 oder 1).

PRINTX; 
x == (y = z); 

Ordnet z zu y (der Wert unverändert bei 4 verlassen); nominell wird dies mit x verglichen, aber der Compiler kann den Vergleich ignorieren. Daher ist x unverändert und immer noch 1.

+0

Danke Jonathan. Ich glaube, die Verwirrung in meinem Teil war, dass ich nicht wusste, dass uns die Frage gestellt werden sollte, um den gesamten Ausdruck als Ganzes zu bewerten. Ich dachte, es wäre Zeile für Zeile – nonameisbetter

+0

@nonameisbetter Viele Programmiersprachen haben Kurzschrift wie folgt - manchmal kann es hilfreich sein zu versuchen, es zu seiner äquivalenten "längeren" Version zu erweitern, wenn die Kurzschrift verwirrend ist. Ich denke, dass dies ein Fall ist, in dem die Kurzschrift nicht hilft, weil sie den Code schwieriger lesbar macht. – EJoshuaS

+1

@EJoshuaS: Der Code ist lausiger Code - es ist nur Zweck pädagogisch, um zu testen, ob Sie, der Leser, die Regeln der Sprache verstehen. Wenn mir jemand einen solchen Code vorlegte, würde ich ihn entweder mit einem Ohr schicken oder sie über den Fehler ihrer Wege aufklären oder sonst alles tun, um zu verhindern, dass er im Hauptcode erscheint. Eine beliebige 'op =' Zuweisung mit einfachen Zuweisungen zu mischen ist ziemlich hässlich. Da hier alle Zahlen festgelegt sind, kann die Berechnung zur Kompilierzeit erfolgen. Der Compiler könnte den Code auf eine Reihe von 4 Aufrufen von printf() mit vorberechneten Werten reduzieren. –

3

Alle Zuweisungsoperatoren haben die gleiche Priorität und eine Assoziation von rechts nach links (was sich darauf auswirkt, wenn mehrere Operatoren gleicher Priorität in einem Ausdruck vorhanden sind).

Dies bedeutet x *= y = z = 4 entspricht x *= (y = (z = 4)). z = 4 muss zuerst ausgewertet werden (was z zu 4 zuweist, und ergibt ein Ergebnis von 4). Die Zuweisung y = ... ergibt dann den Wert y den Wert 4 und ergibt auch ein Ergebnis 4. Die Zuweisung x *= ... dann multipliziert x (die einen Wert 10 hat) von 4, was ein Ergebnis von 40 ergibt.

(Der Grund x *= 3 + 2 gibt x der Wert 10 ist, dass zusätzlich eine höhere Priorität als Zuweisung hat, so x *= 3+2-x *= (3 + 2) entspricht eher als (x *= 3) + 2.)

Wenn die Zuweisungsoperatoren statt von links nach rechts wurden assoziativ, x *= y = z = 4 wäre (((x *= y) = y) = z) = 4, die nicht kompilieren würde.

Verwandte Themen