Domanda

A pochi giorni di nuovo c'è stata una discussione qui sul fatto che l'espressione

  

i = ++ i + 1

invoca UB (Comportamento indefinito) oppure no.

Infine la conclusione è stata fatta che invoca UB come il valore di 'i' sostituire più di una volta tra due punti di sequenza.

Sono stato coinvolto in una discussione con Johannes Schaub nello stesso thread. Secondo lui

  

i = (i, i ++, i) +1 ------ (1) / * invoca UB così * /

ho detto (1) non invoca UB perché gli effetti collaterali dei sotto-espressioni precedenti vengono cancellati dall'operatore virgola '' tra i ed i ++ e tra i ++ e i.

Poi ha dato la seguente spiegazione:

  

"Sì punto sequenza dopo i ++ completa tutti gli effetti collaterali prima di esso, ma non v'è nulla che blocca l'effetto collaterale assegnazione sovrapposizione con l'effetto collaterale di i ++. Il problema fondamentale è che l'effetto collaterale di un'assegnazione è non specificato accadere prima o dopo la valutazione di entrambi gli operandi della cessione, e quindi i punti di sequenza non può fare nulla riguardo alla tutela questo: indica indurre un ordine parziale sequenza: Solo perché c'è un punto sequenza prima e dopo i ++ non intendono tutti gli effetti collaterali sono in sequenza per quanto riguarda i .

     

Inoltre, si noti che solo un punto di sequenza non significa nulla: L'ordine di valutazioni non è dettata dalla forma di codice. E 'dettato da regole semantiche. In questo caso, non v'è alcuna regola semantica dire quando l'effetto collaterale assegnazione avviene per quanto riguarda la valutazione entrambi i suoi operandi o sottoespressioni di questi operandi".

La dichiarazione scritta in "grassetto" mi ha confuso. Per quanto ne so:

"In certi punti specificati nei punti chiamati sequenza sequenza di esecuzione, tutti gli effetti collaterali delle precedenti devono essere completamente e senza effetti collaterali delle valutazioni successive devono aver avuto luogo."

Dal momento che, gli operatori virgola specificano anche ordine di esecuzione l'effetto collaterale di I ++ sono stati cancellati quando si raggiunge l'ultima i.He (Johannes) sarebbe stato giusto avuto l'ordine di valutazione stato non specificato (ma in caso di operatore virgola è ben specificato).

Quindi voglio solo sapere se (1) invoca UB o no ?. Qualcuno può dare un'altra spiegazione valida?

Grazie!

È stato utile?

Soluzione

Lo standard C dice questo circa operatori di assegnazione (C90 6.3.16 o 6.5.16 C99 operatori di assegnazione):

  

L'effetto collaterale di aggiornamento del valore memorizzato dell'operando sinistro deve avvenire tra il precedente e il punto successivo sequenza.

Mi pare che nella dichiarazione:

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

punto sequenza 'precedente' per l'operatore di assegnazione sarebbe il secondo operatore virgola e il 'prossimo' punto sequenza sarebbe la fine dell'espressione. Quindi direi che l'espressione non richiama un comportamento indefinito.

Tuttavia, questa espressione:

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

avrebbe un comportamento indefinito perché l'ordine di valutazione dei 2 operandi dell'operatore di assegnazione non è definita, e in questo caso al posto del problema è quando l'effetto lato operatore assegnazione avviene, il problema è che non si sa se il valore dei usato nel operando maniglia sinistra viene elaborata prima o dopo il lato destro. Questo ordine di valutazione problema non si verifica nel primo esempio perché in quella espressione del valore di i non è effettivamente utilizzato nel lato sinistro - tutto che l'operatore assegnazione è interessato è il "Ivalue-ness" di i .

Ma penso anche che tutto questo è abbastanza impreciso (e la mia comprensione delle sfumature coinvolti sono abbastanza abbozzato) che io non sarei sorpreso se qualcuno mi può convincere altrimenti (su entrambi i conta).

Altri suggerimenti

Credo che la seguente espressione sicuramente è indefinito comportamento.

i + ((i, i++, i) + 1)

La ragione è che l'operatore virgola specifica punti di sequenza tra le sottoespressioni tra parentesi ma non specifica dove in quella sequenza avviene la valutazione dell'operando sinistra +. Una possibilità è tra il i++ punti sequenza circostante e questo viola il 5/4 come i viene scritto tra due punti di sequenza, ma è anche letto due volte tra gli stessi punti di sequenza e non solo per determinare il valore da memorizzare, ma anche per determinare la valore del primo operando all'operatore +.

Questo comportamento ha anche undefined.

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

Ora, io non sono così sicuro di questa affermazione.

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

Anche se si applicano gli stessi principi, i deve essere "valutato" come un lvalue modificabile e può essere fatto in qualsiasi momento, ma non sono convinto che il suo Valore è mai leggere come parte di questo. (O c'è un altro vincolo che l'espressione viola per causare UB?)

Il (i, i++, i) espressione secondaria avviene come parte della determinazione del valore da memorizzare e sub-espressione contiene un punto sequenza dopo la memorizzazione di un valore di i. Non vedo alcun modo che questo non richiederebbe l'effetto collaterale di i++ di essere completato prima della determinazione del valore da memorizzare e quindi il primo punto possibile che si potrebbe verificare l'effetto collaterale di assegnazione.

Dopo questo punto il valore di i sequnce viene letto più di una volta e solo per determinare il valore che verrà memorizzato torna a i, quindi questa ultima parte è bene.

i=(i,i++,i)+1 ------ (1) /* invokes UB as well */

E non richiama un comportamento indefinito. L'effetto collaterale di i++ avverrà prima della valutazione del successivo punto sequenza, che è indicato dalla seguente virgola, e anche prima della cessione.

Nizza lingua sudoku, però. : -)

modifica:. C'è una spiegazione più elaborata qui

ero confuso in principio per quanto riguarda (litb) dichiarazione Johannes' ma ha detto che in:

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


  Se è l'assegnazione, ed è un incremento. :s: è un punto sequenza, allora gli effetti collaterali possono essere sequenziati come segue tra i punti di sequenza: (i :s: i++< a ><n> :s: i) + 1. Il valore della i scalare è stata cambiata due volte tra il primo e il secondo punto sequenza qui. L'ordine in cui l'assegnazione e l'incremento avviene non è specificato, e dal momento che tra loro non c'è punto sequenza, non è nemmeno atomico rispetto ciascuna other.This è un ordinamento consentito consentiti dall'ordinamento imprecisato di questi effetti collaterali.

     

Questo è diverso da (i++, i++), perché l'ordine di valutazione delle due sottoespressioni è da sinistra a destra, e nel punto di sequenza tra di loro, l'incremento della precedente valutazione è completo, e l'incremento successivo non hanno ancora preso posto. Ciò impone che non v'è alcun cambiamento del valore della i tra due punti di sequenza, il che rende (i++, i++)
valida   

Questo mi ha fatto pensare alla sequenza di cui parla litb non è valido perché come da C99:

  

6.5.16.1 (2) In semplice assegnazione (=), il valore dell'operando di destra viene convertito nel tipo dell'espressione di assegnazione e sostituisce il valore memorizzato nell'oggetto indicato dall'operando sinistro.

vale a dire. il valore dell'operando destra deve essere conosciuto prima l'effetto collaterale assegnazione (modifica del valore memorizzato nell'oggetto corrispondente all'operando sinistra)

  

6.5.17 (2) L'operando sinistro dell'operatore virgola viene valutata come espressione vuoto; c'è un punto sequenza dopo la sua valutazione. Poi viene valutata l'operando di destra; il risultato ha il suo tipo e il valore.

vale a dire. l'operando più a destra dell'operazione comma deve essere valutato per conoscere il valore e il tipo dell'espressione virgola (e il valore del l'operando di destra per il mio esempio).

Quindi, in questo caso, il 'precedente punto sequenza' per l'effetto collaterale assegnazione sarebbe, in effetti, essere più a destra il funzionamento virgola. Il possibile sequenza citato da Johannes non è valido.

Si prega di correggermi se sbaglio.


scroll top