Szukaj…


Uwagi

Międzynarodowa norma ISO / IEC 9899: 201x Języki programowania - C

Dostęp do lotnego obiektu, modyfikacja obiektu, modyfikacja pliku lub wywołanie funkcji wykonującej którąkolwiek z tych operacji to wszelkie skutki uboczne , które są zmianami w stanie środowiska wykonawczego.

Obecność punktu sekwencyjnego między oceną wyrażeń A i B oznacza, że każde obliczenie wartości i efekt uboczny związany z A jest sekwencjonowane przed każdym obliczeniem wartości i efektem ubocznym związanym z B.

Oto pełna lista punktów sekwencji z załącznika C internetowego projektu przed publikacją w 2011 r. Standardu języka C:

Punkty sekwencji

1 Poniżej przedstawiono punkty sekwencji opisane w 5.1.2.3:

  • Między ocenami desygnatora funkcji a rzeczywistymi argumentami w wywołaniu funkcji i rzeczywistym wywołaniem. (6.5.2.2).
  • Między ocenami pierwszego i drugiego argumentu następujących operatorów: logiczne AND && (6.5.13); logiczne OR || (6.5.14); przecinek , (6.05.17).
  • Między ocenami pierwszego argumentu warunkowego ? : operator i cokolwiek z drugiego i trzeciego argumentu jest oceniane (6.5.15).
  • Koniec pełnego deklaratora: deklaratory (6.7.6);
  • Między oceną pełnego wyrażenia a następnym pełnym wyrażeniem do oceny. Oto pełne wyrażenia: inicjator, który nie jest częścią literału złożonego (6.7.9); wyrażenie w wyrażeniu wyrażeniowym (6.8.3); kontrolne wyrażenie instrukcji wyboru ( if lub switch ) (6.8.4); kontrolujące wyrażenie instrukcji while lub do (6.8.5); każde (opcjonalne) wyrażenie instrukcji for (6.8.5.3); (opcjonalne) wyrażenie w instrukcji return (6.8.6.4).
  • Bezpośrednio przed powrotem funkcji biblioteki (7.1.4).
  • Po działaniach związanych z każdym sformatowanym specyfikatorem konwersji funkcji wejścia / wyjścia (7.21.6, 7.29.2).
  • Bezpośrednio przed i bezpośrednio po każdym wywołaniu funkcji porównawczej, a także między każdym wywołaniem funkcji porównawczej a każdym ruchem obiektów przekazywanych jako argumenty do tego wywołania (7.22.5).

Wyrażenia sekwencyjne

Sekwencjonowane są następujące wyrażenia:

a && b
a || b
a , b
a ? b : c
for ( a ; b ; c ) { ... }

We wszystkich przypadkach wyrażenie a jest w pełni oceniane i wszystkie działania niepożądane są stosowane przed oceną b lub c . W czwartym przypadku oceniany będzie tylko jeden z b lub c . W ostatnim przypadku b jest w pełni oceniane, a wszystkie działania niepożądane są stosowane przed oceną c .

We wszystkich przypadkach ocena ekspresji a jest sekwencjonowana przed ocenami b lub c (alternatywnie oceny b i csekwencjonowane po ocenie a ).

Tak więc wyrażenia takie jak

x++ && x++
x++ ? x++ : y++ 
(x = f()) && x != 0
for ( x = 0; x < 10; x++ ) { ... }
y = (x++, x++);

mają dobrze określone zachowanie.

Wyrażenia niesekwencjonowane

C11

Następujące wyrażenia nie mają konsekwencji :

a + b;
a - b;
a * b;
a / b;
a % b;
a & b;
a | b;

W powyższych przykładach wyrażenie a może być ocenione przed lub po wyrażeniu b , b może być ocenione przed a , lub nawet mogą być zmieszane, jeśli odpowiadają kilku instrukcjom.

Podobna zasada dotyczy wywołań funkcji:

f(a, b);

Tutaj nie tylko i a b są unsequenced (to znaczy , operator wywołania funkcji wywołuje punkt sekwencji), a także f , ekspresji, który określa funkcję, która ma być wykorzystane.

Efekty uboczne można zastosować natychmiast po ocenie lub odłożyć na później.

Wyrażenia takie jak

x++ & x++;
f(x++, x++); /* the ',' in a function call is *not* the same as the comma operator */
x++ * x++;
a[i] = i++;

lub

x++ & x;
f(x++, x);
x++ * x;
a[i++] = i;

spowoduje niezdefiniowane zachowanie, ponieważ

  • modyfikacja obiektu i każdy inny dostęp do niego muszą być zsekwencjonowane
  • kolejność oceny i kolejność stosowania efektów ubocznych 1 nie jest określona.

1 Wszelkie zmiany stanu środowiska wykonawczego.

Wyrażenia nieokreślone sekwencyjnie

Wywołania funkcyjne jako f(a) zawsze oznaczają punkt sekwencyjny między oceną argumentów i desygnatora (tutaj f i a ) a rzeczywistym wywołaniem. Jeśli dwa takie wywołania nie są konsekwentne, dwa wywołania funkcji są sekwencyjnie nieokreślone, to znaczy jedno jest wykonywane przed drugim, a kolejność jest nieokreślona.

unsigned counter = 0;

unsingned account(void) {
   return counter++;
}

int main(void) {
   printf("the order is %u %u\n", account(), account());
}

Ta niejawna podwójna modyfikacja counter podczas oceny argumentów printf jest poprawna, po prostu nie wiemy, które z wywołań jest pierwsze. Ponieważ zamówienie nie jest określone, może się różnić i nie można na nim polegać. Tak więc wydruk może być:

kolejność wynosi 0 1

lub

kolejność wynosi 1 0

Analogiczne oświadczenie do powyższego bez wywołania funkcji pośredniej

   printf("the order is %u %u\n", counter++, counter++); // undefined behavior

ma niezdefiniowane zachowanie, ponieważ nie ma punktu sekwencji między dwiema modyfikacjami counter .



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow