Поиск…


замечания

Международный стандарт ISO / IEC 9899: 201x Языки программирования - C

Доступ к изменчивому объекту, изменение объекта, изменение файла или вызов функции, выполняющей любую из этих операций, являются всеми побочными эффектами , которые являются изменениями состояния среды выполнения.

Наличие точки последовательности между оценкой выражений A и B означает, что каждое вычисление значения и побочный эффект, связанные с A, секвенируются перед вычислением каждого значения и побочным эффектом, связанным с B.

Ниже приведен полный список точек последовательности из Приложения C онлайн-проекта предварительной публикации стандарта языка C на 2011 год :

Точки последовательности

1 Ниже приведены точки последовательности, описанные в 5.1.2.3:

  • Между оценками имени функции и фактическими аргументами в вызове функции и фактическим вызовом. (6.5.2.2).
  • Между оценками первого и второго операндов следующих операторов: логическое AND && (6.5.13); логический ИЛИ || (6.5.14); запятая , (6.5.17).
  • Между оценками первого операнда условного ? : оператор и в зависимости от второго и третьего операндов (6.5.15).
  • Конец полного декларатора: деклараторы (6.7.6);
  • Между оценкой полного выражения и следующим полным выражением, которое должно быть оценено. Ниже приведены полные выражения: инициализатор, не являющийся частью составного литерала (6.7.9); выражение в выражении выражения (6.8.3); управляющее выражение оператора выбора ( if или switch ) (6.8.4); управляющее выражение while или do (6.8.5); каждое из (необязательных) выражений оператора for (6.8.5.3); (необязательное) выражение в операторе return (6.8.6.4).
  • Непосредственно перед возвратом функции библиотеки (7.1.4).
  • После действий, связанных с каждым форматированным спецификатором преобразования функции ввода / вывода (7.21.6, 7.29.2).
  • Непосредственно перед и сразу после каждого вызова функции сравнения, а также между любым вызовом функции сравнения и любым перемещением объектов, переданных в качестве аргументов для этого вызова (7.22.5).

Последовательные выражения

Следующие выражения секвенированы :

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

Во всех случаях выражение a полностью оценивается и все побочные эффекты применяются до того, как оцениваются b или c . В четвертом случае будет оцениваться только один из b или c . В последнем случае b полностью оценивается и все побочные эффекты применяются до оценки c .

Во всех случаях оценка выражения a секвенируется до оценок b или c (поочередно оценки b и c секвенируются после оценки a ).

Таким образом, выражения типа

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

имеют четко определенное поведение.

Непоследовательные выражения

C11

Следующие выражения не подвержены влиянию :

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

В приведенных выше примерах выражение a может быть оценено до или после выражения b , b может быть оценено до a , или они могут даже смешиваться, если они соответствуют нескольким инструкциям.

Аналогичное правило выполняется для вызовов функций:

f(a, b);

Здесь не только и a b являются unsequenced (то есть , оператор в вызове функции не создает точку последовательности) , но и f , выражение , которое определяет функцию , которая должна быть вызвана.

Побочные эффекты могут применяться сразу после оценки или отсрочки до более поздней точки.

Выражения вроде

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

или же

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

приведет к неопределенному поведению, потому что

  • модификация объекта и любой другой доступ к нему должны быть упорядочены
  • порядок оценки и порядок применения побочных эффектов 1 не указаны.

1 Любые изменения состояния среды выполнения.

Неопределенно упорядоченные выражения

Функциональные вызовы как f(a) всегда подразумевают точку последовательности между оценкой аргументов и обозначением (здесь f и a ) и фактическим вызовом. Если два таких вызова не имеют последовательности, два вызова функции неопределенно секвенированы, то есть один выполняется перед другим, а порядок не указан.

unsigned counter = 0;

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

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

Эта неявная двукратная модификация counter при оценке аргументов printf действительна, мы просто не знаем, какой из вызовов на первом месте. Поскольку заказ не указан, он может меняться и не может зависеть. Таким образом, распечатка может быть:

порядок равен 0 1

или же

заказ 1 0

Аналогичное утверждение выше, без вызова промежуточной функции

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

имеет неопределенное поведение, поскольку между двумя модификациями counter нет точки последовательности.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow