2013-07-04 21 views
12

Die angeblich „clever“ (aber eigentlich ineffizient) Art und Weise zwei Integer-Variablen von Swapping, anstelle der Verwendung von temporären Speicher, beinhaltet oft diese Zeile: Gibt es Sequenzpunkte im Ausdruck a^= b^= a^= b, oder ist es undefiniert?

int a = 10; 
int b = 42; 

a ^= b ^= a ^= b; /*Here*/ 

printf("a=%d, b=%d\n", a, b); 

Aber ich frage mich, Verbindung Zuweisungsoperatoren wie ^= sind keine Sequenzpunkte, oder? Bedeutet dies, dass es tatsächlich undefiniertes Verhalten ist?

+2

Wenn Sie Code schreiben, der schwer zu sagen ist, was vor sich geht, fragen Sie sich, ob es einen einfacheren Weg gibt, den ein zukünftiger Entwickler verstehen könnte? –

+1

Beachten Sie, dass, wenn Sie dies in C++ - Code gesehen haben, C++ verschiedene Regeln für die Zuweisungsoperatoren hat, die bestimmte Konstrukte zulassen (ich bin mir nicht sicher), die in C. nicht möglich sind. – hvd

+3

mögliches Duplikat von [Sequenzpunkt - Xor Swap on Array bekomme ein falsches Ergebnis] (http://stackoverflow.com/questions/9958514/sequence-point-xor-swap-on-array-get-wrong-result) –

Antwort

17
a ^= b ^= a ^= b; /*Here*/ 

Es ist undefiniertes Verhalten.

Sie ändern ein Objekt (a) mehr als einmal zwischen zwei Sequenzpunkten.

(C99, 6.5p2) „zwischen dem vorherigen und nächsten Sequenz Punkt ein Objekt hat seinen gespeicherten Wert höchstens einmal durch die Auswertung eines Ausdrucks geändert hat.

einfache Zuweisungen sowie Verbindung Zuweisungen einführen keine Punktfolge. Hier gibt es eine Sequenz Punkt vor dem Ausdruck Aussage Ausdruck ist und nach dem Ausdruck Aussage.

Sequence Punkte aufgelistet sind in Anhang C (informativ) der C99 und C11-Standard.

13

^= keine Sequenzpunkte, sie sind

Sie sind es nicht.

Bedeutet dies, dass es tatsächlich undefiniertes Verhalten ist?

Ja ist es. Benutze diese "clevere" Technik nicht.

+0

Danke für die Bestätigung. Mach dir keine Sorgen, ich habe nie beabsichtigt, es überhaupt zu benutzen. – Medinoc

7

Es gibt keine Sequenzpunkte in diesem Ausdruck, sodass ein undefiniertes Verhalten entsteht.

Man könnte es trivialer beheben und die meisten der Prägnanz behalten durch das Komma-Operator, die Sequenzpunkte einführt:

a ^= b, b ^= a, a ^= b; 
+1

Sie können es jetzt auch auf drei verschiedene Zeilen setzen. Es macht eine schöne Box, wenn Sie sich um diese Dinge kümmern. – Thomas

5

Die Reihenfolge der Auswertung der ^= Betreiber ist gut definiert. Was nicht genau definiert ist, ist die Reihenfolge, in der a und b modifiziert werden.

a ^= b ^= a ^= b; 

entspricht

a ^= (b ^= (a ^= b)); 

Ein Bediener kann nicht ausgewertet werden, bevor ihre Argumente ausgewertet werden, so ist es auf jeden Fall a ^= b zuerst gehen auszuführen.

Der Grund für dieses undefinierte Verhalten liegt darin, dass es dem Compiler erlaubt ist, die Flexibilität in Optimierungen zu ändern, und die Variablenwerte in beliebiger Reihenfolge ändern können.Es könnte wählen, dies zu tun:

int a1 = a^b; 
int b1 = b^a1; 
int a2 = a^b1; 
a = a1; 
a = a2; 
b = b1; 

oder dies:

int a1 = a^b; 
int b1 = b^a1; 
a = a1; 
int a2 = a^b1; 
a = a2; 
b = b1; 

oder auch diese:

int a1 = a^b; 
int b1 = b^a1; 
int a2 = a^b1; 
a = a2; 
a = a1; 
b = b1; 

Wenn der Compiler nur eine dieser drei Möglichkeiten wählen, könnten die Dinge zu tun, das wäre nur "unspezifiziertes" Verhalten. Der Standard geht jedoch weiter und macht dies zu einem "undefinierten" Verhalten, was es dem Compiler grundsätzlich erlaubt, anzunehmen, dass es nicht einmal passieren kann.

+0

erste Erklärung ist entscheidend, aber ich konnte Grund nicht verstehen: * 'vor-modifizierten oder die post-modifizierten Werte' * –

+1

Dies ist irreführend. Es gibt nichts, was verhindert, dass die Nebenwirkung eines Ausdrucks auftritt, nachdem die Bewertung bereits abgeschlossen ist. Das Ergebnis von 'a^= b' ist 'a^b', und als Nebeneffekt wird 'a' auf dieses Ergebnis gesetzt. * Wenn * 'a' auf dieses Ergebnis gesetzt ist, ist es nicht spezifiziert. Insbesondere gibt es nichts, was erfordert, dass * beendet ist * bevor * das äußere "a^= ..." beginnt. – hvd

+0

@hvd: Ich stimme zu. Ich habe versucht, es umzuformulieren, um es klarer zu machen. –