2010-07-24 19 views
9

Ho il seguente codice diComportamento di un'espressione: definito o non definito?

int m[4]={1,2,3,4}, *y; 
y=m; 
*y = f(y++); // Expression A 

Il mio amico mi ha detto che Expression A ha un comportamento ben definito, ma io non sono sicuro se sia corretta.

Secondo lui la funzione f() introduce uno sequence point in mezzo e quindi il comportamento è ben definito.

Qualcuno si prega di chiarire.

P.S: So che non dovremmo scrivere tale codice per scopi pratici. È solo per lo scopo dell'apprendimento. :)

+3

Dico no. A questo mi dice 'gcc'. – kennytm

risposta

15

Nella migliore delle ipotesi, il codice in questione ha un comportamento non specificato. Per gli operatori incaricati, "l'ordine di valutazione degli operandi non è specificato" (C99 §6.5.16/4).

Se l'operando di sinistra viene valutato per primo, il risultato di f(y++) verrà archiviato in m[0]. Se l'operando destro viene valutato per primo, il risultato verrà archiviato in m[1].

Per quanto riguarda se il comportamento è indefinito, il punto rilevante è:

tra il precedente e successivo punto di sequenza di un oggetto deve avere il suo valore memorizzato modi fi cato al massimo una volta dalla valutazione di un'espressione. Inoltre, il valore precedente deve essere letto solo per determinare il valore da memorizzare (C99 §6.5/2).

Se il lato sinistro viene valutata per prima, poi abbiamo conciliarsi con la seconda frase, perché l'ordine è:

  1. Il valore di y viene letto sul lato sinistro per dereferenziarlo
  2. Il il valore di viene letto sul lato destro per incrementarlo
  3. C'è un punto di sequenza dopo la valutazione degli argomenti della funzione (quindi, l'effetto collaterale di y++ è completo e viene scritto su)

Al punto 1, il "valore precedente" di viene letto ma per uno scopo diverso da "determinare il valore da memorizzare". Pertanto, il comportamento è effettivamente indefinito perché un ordine di valutazione valido produce un comportamento non definito.

+2

+1. Credo che sia anche indefinito, perché le valutazioni di '* y' e' y ++ 'non sono seguite e quest'ultimo induce un effetto collaterale su' y'. – avakar

+0

Grazie James, la tua risposta è perfetta. AC :-) –

0

EDIT: questo non è corretto, tuttavia lo lascio qui perché la discussione che segue nei commenti è piuttosto illuminante, e spero utile.

È ben definito in base all'ordine di valutazione degli operatori in C (o C++).

Valutazione delle forze di assegnazione del lato destro dell'espressione. L'applicazione della funzione forza la valutazione dei suoi argomenti prima, quindi l'effetto sembra abbastanza chiaro (anche se non ho provato a farlo funzionare, quindi sentitevi liberi di correggermi!). Possiamo riscrivere questo utilizzando le variabili temporanee (io li chiamo T0 e T1), e credo che questo potrebbe essere un po 'più chiaro:

t0 = y++; 
t1 = f(t0); 
*y = t1; 

Il termine "punto di sequenza" è un po' di una falsa pista. Un punto di sequenza non è realmente creato, ma è solo la conseguenza di avere un rigoroso ordine di valutazione definito per la lingua. EDITOR: Mentre questa risposta sembra intellettualmente soddisfacente, la risposta di James McNellis cita il pezzo rilevante della specifica C99 che afferma che l'ordine di valutazione dell'assegnazione è non ben definito. Pieno credito per lui per aver effettivamente controllato i suoi fatti. Ho intenzione di rivedere la mia risposta da "è ben definito" a "è probabilmente ben definito rispetto a un particolare compilatore", poiché penso che sia improbabile che la maggior parte dei compilatori cambierà regolarmente l'ordine in cui emettono tale codice (Dico "probabilmente" per giustificare un'ottimizzazione molto aggressiva).

+2

_Assegnazione delle forze di valutazione del lato destro dell'espressione per prima. Questo non è vero: l'ordine di valutazione non è specificato. –

+1

Dove afferma che il lato destro di un compito deve essere valutato per primo? – jalf

+0

Grazie, ho appena modificato la mia risposta per renderlo conto e grazie per avermi insegnato qualcosa di nuovo su C :) – Gian

1

L'espressione non è ben definito:

Una valida interpretazione dell'espressione è:

(1) int* t0 = y++; 
(2) int t1 = f(t0); 
(3) int& t2 = *y; 
----------------- 
t2 = t1; 

Un'interpretazione ugualmente validi dell'espressione è:

(1) int& t2 = *y; 
(2) int* t0 = y++; 
(3) int t1 = f(t0); 
----------------- 
t2 = t1; 

Entrambi questi sono vaalid e generare risultati diversi. Quindi l'espressione ha un risultato indefinito.

+1

In generale, il fatto che un'espressione possa avere due risultati diversi significa semplicemente che il risultato è * non specificato *. Tuttavia, in questo caso particolare il risultato è davvero indefinito in quanto i calcoli di 't0' e' t2' possono verificarsi in qualsiasi ordine e 't0' ha effetti collaterali su' y' mentre 't2' usa il valore di' y'. – avakar

13

Hai assolutamente ragione sulla chiamata di funzione che introduce un punto di sequenza. Tuttavia, quel punto di sequenza non salva la situazione nel tuo caso.

Considerate questo semplice esempio prima

i = some_function(i++); 

E 'valida? Sì. Perché? È valido perché il punto di sequenza introdotto dalla funzione (quella di cui si sta parlando) separa due modifiche di i l'una dall'altra, rendendo così il codice valido. Non esiste un ordine di valutazione di questa espressione che comporti la modifica di i due volte senza un punto di sequenza intermedio.

Tuttavia, torniamo alla tua variante

*y = f(y++); 

In questo caso quel punto sequenza esiste pure. Tuttavia, la lingua non fornisce alcuna garanzia circa l'ordine di valutazione dell'operatore = (ovvero: la lingua non fornisce alcuna garanzia su quale operando dell'operatore di assegnazione viene valutato per primo: a sinistra oa destra). È abbastanza possibile per il compilatore valutare prima il lato sinistro (*y), l'argomento della funzione secondo (y++), quindi chiamare la funzione e quindi eseguire l'assegnazione effettiva. In questo scenario potenziale i primi due passaggi - la lettura di e la modifica di - non sono separati da un punto di sequenza. Quindi, il comportamento non è definito.

+1

@Ben Voigt: stavo parlando del relativo ordine di valutazione degli operandi dell'operatore '=', cioè se LHS o RHS sono valutati per primi. – AnT

Problemi correlati