C Language
Punti di sequenza
Ricerca…
Osservazioni
Standard internazionale ISO / IEC 9899: 201x Linguaggi di programmazione - C
L'accesso a un oggetto volatile, la modifica di un oggetto, la modifica di un file o il richiamo di una funzione che esegue una di queste operazioni sono tutti effetti collaterali , che sono cambiamenti nello stato dell'ambiente di esecuzione.
La presenza di un punto di sequenza tra la valutazione delle espressioni A e B implica che ogni calcolo del valore ed effetto collaterale associato ad A viene sequenziato prima di ogni calcolo del valore ed effetto collaterale associato a B.
Ecco l'elenco completo dei punti di sequenza dell'allegato C della bozza di pre-pubblicazione online 2011 dello standard di lingua C:
Punti di sequenza
1 I seguenti sono i punti di sequenza descritti in 5.1.2.3:
- Tra le valutazioni del designatore di funzioni e gli argomenti effettivi in una chiamata di funzione e la chiamata effettiva. (6.5.2.2).
- Tra le valutazioni del primo e del secondo operando dei seguenti operatori: AND logico
&&
(6.5.13); OR logico||
(6.5.14); comma,
(6.5.17).- Tra le valutazioni del primo operando del condizionale
? :
viene valutato l'operatore e il secondo e il terzo operando (6.5.15).- La fine di un dichiarante completo: dichiarators (6.7.6);
- Tra la valutazione di un'espressione completa e la successiva espressione completa da valutare. Le seguenti sono espressioni complete: un inizializzatore che non fa parte di un letterale composto (6.7.9); l'espressione in un'espressione (6.8.3); l'espressione di controllo di una dichiarazione di selezione (
if
oswitch
) (6.8.4); l'espressione di controllo di unwhile
odo
statement (6.8.5); ciascuna delle espressioni (facoltative) di una dichiarazionefor
(6.8.5.3); l'espressione (facoltativa) in una dichiarazione direturn
(6.8.6.4).- Immediatamente prima che una funzione di libreria ritorni (7.1.4).
- Dopo le azioni associate a ciascun identificatore di conversione della funzione di input / output formattato (7.21.6, 7.29.2).
- Immediatamente prima e immediatamente dopo ogni chiamata a una funzione di confronto, e anche tra qualsiasi chiamata a una funzione di confronto e qualsiasi movimento degli oggetti passati come argomenti a quella chiamata (7.22.5).
Espressioni sequenziate
Le seguenti espressioni sono sequenziate :
a && b
a || b
a , b
a ? b : c
for ( a ; b ; c ) { ... }
In tutti i casi, l'espressione a
viene valutata completamente e tutti gli effetti collaterali vengono applicati prima che sia valutato b
o c
. Nel quarto caso, verrà valutato solo uno di b
o c
. Nell'ultimo caso, b
viene completamente valutato e tutti gli effetti collaterali vengono applicati prima che c
venga valutata.
In tutti i casi, la valutazione dell'espressione a
sequenziato prima le valutazioni di b
o c
(alternativamente, le valutazioni di b
e c
sono in sequenza dopo la valutazione di a
).
Quindi, espressioni come
x++ && x++
x++ ? x++ : y++
(x = f()) && x != 0
for ( x = 0; x < 10; x++ ) { ... }
y = (x++, x++);
avere un comportamento ben definito
Espressioni senza conseguenze
Le seguenti espressioni non sono state seguite :
a + b;
a - b;
a * b;
a / b;
a % b;
a & b;
a | b;
Negli esempi precedenti, l'espressione a
può essere valutata prima o dopo l'espressione b
, b
può essere valutata prima di a
, o possono anche essere mescolati se corrispondono a più istruzioni.
Una regola simile vale per le chiamate di funzione:
f(a, b);
Qui non solo a
e b
sono non in sequenza (cioè la ,
operatore in una chiamata di funzione non produce un punto sequenza), ma anche f
, l'espressione che determina la funzione che deve essere chiamato.
Gli effetti collaterali possono essere applicati immediatamente dopo la valutazione o posticipati fino a un momento successivo.
Espressioni come
x++ & x++;
f(x++, x++); /* the ',' in a function call is *not* the same as the comma operator */
x++ * x++;
a[i] = i++;
o
x++ & x;
f(x++, x);
x++ * x;
a[i++] = i;
produrrà un comportamento indefinito perché
- una modifica di un oggetto e qualsiasi altro accesso ad essa deve essere sequenziata
- l'ordine di valutazione e l'ordine in cui vengono applicati gli effetti collaterali 1 non è specificato.
1 Eventuali cambiamenti nello stato dell'ambiente di esecuzione.
Espressioni a sequenza indeterminata
Le chiamate di funzione come f(a)
implicano sempre un punto di sequenza tra la valutazione degli argomenti e il designatore (qui f
e a
) e la chiamata effettiva. Se due di tali chiamate vengono annullate, le due chiamate di funzione vengono sequenzialmente indeterminate, ovvero, una viene eseguita prima dell'altro e l'ordine non è specificato.
unsigned counter = 0;
unsingned account(void) {
return counter++;
}
int main(void) {
printf("the order is %u %u\n", account(), account());
}
Questa modifica implicita del counter
durante la valutazione degli argomenti di printf
è valida, semplicemente non sappiamo quale delle chiamate viene prima. Poiché l'ordine non è specificato, può variare e non può dipendere da. Quindi la stampa potrebbe essere:
l'ordine è 0 1
o
l'ordine è 1 0
L'affermazione analoga a quanto sopra senza chiamata di funzione intermedia
printf("the order is %u %u\n", counter++, counter++); // undefined behavior
ha un comportamento indefinito perché non esiste un punto di sequenza tra le due modifiche del counter
.