2013-07-04 12 views
12

Il modo in cui presumibilmente "intelligente" (ma in realtà inefficiente) di scambiare due variabili intere, invece di utilizzare il deposito temporaneo, spesso comporta questa linea: Ci sono punti di sequenza nell'espressione a^= b^= a^= b, o è indefinito?

int a = 10; 
int b = 42; 

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

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

Ma mi chiedo, composti operatori di assegnazione come ^= sono non punti di sequenza, vero? Significa che è in realtà un comportamento indefinito?

+2

Se scrivi un codice che è difficile dire cosa sta succedendo, chiediti se esiste un modo più semplice che un futuro sviluppatore possa capire? –

+1

Si noti che se si è visto questo in codice C++, C++ ha regole diverse per gli operatori di assegnazione che consentono determinati costrutti (non sono sicuro di questo) che non sono definiti in C. – hvd

+3

possibile duplicato di [Punto sequenza - Xor Swap on Array ottiene risultati errati] (http://stackoverflow.com/questions/9958514/sequence-point-xor-swap-on-array-get-wrong-result) –

risposta

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

È un comportamento non definito.

Si sta modificando un oggetto (a) più di una volta tra due punti di sequenza.

(C99, 6.5p2) "Tra il precedente e successivo punto sequenza un oggetto deve avere il suo valore memorizzato modificato al più una volta dalla valutazione di un'espressione.

assegnazioni semplice così come composto assegnazioni non introducono un punto di sequenza. Qui c'è un punto sequenza prima l'espressione istruzione di espressione e dopo l'istruzione di espressione.

punti di sequenza sono elencati nell'allegato C (informativa) del C99 e C11 standard.

13

^= non sono punti di sequenza, sono essi

Essi non sono.

Ciò significa che è in realtà un comportamento non definito?

Sì, lo è. Non usare questa tecnica "intelligente".

+0

Grazie per la conferma. Non preoccuparti, non ho mai avuto intenzione di usarlo in primo luogo. – Medinoc

7

Non ci sono punti di sequenza in quell'espressione, quindi produce un comportamento non definito.

Si potrebbe risolvere il problema banalmente e mantenere la maggior parte del succinctness utilizzando l'operatore virgola, che fa introdurre punti di sequenza:

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

A questo punto puoi metterlo su tre linee diverse. Sarà una bella scatola, se ci tieni a queste cose .. – Thomas

5

L'ordine di valutazione delle ^= operatori è ben definito. Ciò che non è ben definito è l'ordine in cui vengono modificati a e b.

a ^= b ^= a ^= b; 

è equivalente a

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

L'operatore non può essere valutata prima suoi argomenti vengono valutati, quindi è sicuramente andando ad eseguire a ^= b prima.

Il motivo per cui questo comportamento è indefinito è che, per dare al compilatore maggiore flessibilità nelle ottimizzazioni, è consentito modificare i valori delle variabili in qualsiasi ordine esso scelga.Si potrebbe scegliere di fare questo:

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

o questo:

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

o anche questo:

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

Se il compilatore potrebbe scegliere solo uno di questi tre modi di fare le cose, questo sarebbe solo un comportamento "non specificato". Tuttavia, lo standard va oltre e rende questo comportamento "indefinito", che sostanzialmente consente al compilatore di presumere che non può nemmeno accadere.

+0

la prima spiegazione è definitiva, ma non ho potuto capire la ragione: * 'valori pre-modificati o post-modificati * * –

+1

Questo è fuorviante. Non c'è nulla che impedisca l'effetto collaterale di un'espressione dopo che la valutazione è già stata completata. Il risultato di 'a^= b' è' a^b', e come effetto collaterale, 'a' è impostato su quel risultato. * Quando * 'a' è impostato su quel risultato non specificato. In particolare, non c'è nulla che richieda di aver finito * prima * inizia l'esterno 'a^= ...'. – hvd

+0

@hvd: sono d'accordo. Ho provato a riformularlo per renderlo più chiaro. –

Problemi correlati