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

А точка последовательности определяет любую точку в компьютерная программа с исполнение при котором гарантируется, что все побочные эффекты предыдущих оценок, и никаких побочных эффектов от последующих оценок еще не было. Они часто упоминаются со ссылкой на C и C ++, потому что они являются основной концепцией для определения достоверности и, если они допустимы, возможных результатов выражений. Иногда необходимо добавить дополнительные точки последовательности, чтобы сделать выражение определенным и гарантировать единый допустимый порядок оценки.

С C ++ 11, термин «точка последовательности» заменен на «последовательность». Есть три возможности:[1][2][3]

  1. Оценка выражения может быть последовательность до оценка другого выражения, или, что эквивалентно, оценка другого выражения последовательность после что из первого.
  2. Оценка выражений неопределенная последовательность, это означает, что один из них следует за другим, но не определен.
  3. Оценка выражений непоследовательный.

Выполнение непоследовательных оценок может перекрываться, что приводит к катастрофическим последствиям. неопределенное поведение если они поделятся государственный. Такая ситуация может возникнуть в параллельные вычисления, вызывая условия гонки. Однако это уже может возникнуть в простых несовпадающих ситуациях, таких как (а = 1) + (Ь = а), где часть задания а (например, половина битов) может произойти до б = а, а остальное - после этого, так что после вычисления выражения б может содержать бессмысленное промежуточное состояние а.

Примеры двусмысленности

Рассмотрим два функции f () и грамм(). В C и C ++ + оператор не связан с точкой последовательности, и поэтому в выражение f () + g () возможно, что либо f () или же грамм() будет выполнено первым. Оператор запятая вводит точку последовательности, и поэтому в коде f (), g () порядок оценки определен: первый f () называется, а затем грамм() называется.

Точки последовательности также вступают в игру, когда одна и та же переменная изменяется более одного раза в одном выражении. Часто цитируемым примером является C выражение я = я ++, который, по-видимому, оба присваивает я его предыдущее значение и увеличивается я. Окончательное значение я неоднозначен, потому что, в зависимости от порядка вычисления выражения, приращение может происходить до, после или чередоваться с присвоением. Определение конкретного языка может указывать одно из возможных поведений или просто говорить, что поведение неопределенный. В C и C ++ вычисление такого выражения приводит к неопределенному поведению.[4] Другие языки, например C # определить приоритет оператора присваивания и приращения таким образом, чтобы результат выражения я = я ++ гарантировано.

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

В C[5] и C ++,[6] точки последовательности встречаются в следующих местах. (В C ++ перегруженные операторы действуют как функции, и поэтому операторы, которые были перегружены, вводят точки последовательности так же, как вызовы функций.)

  1. Между вычислением левого и правого операндов && (логическое И ), || (логическое ИЛИ ) (как часть оценка короткого замыкания ), и операторы запятой. Например, в выражении *п++ != 0 && *q++ != 0, все побочные эффекты подвыражения *п++ != 0 завершаются до любой попытки доступа q.
  2. Между вычислением первого операнда троичного оператор "вопросительный знак" и второй или третий операнд. Например, в выражении а = (*п++) ? (*п++) : 0 после первого *п++, что означает, что он уже был увеличен к моменту выполнения второго экземпляра.
  3. В конце полного выражения. В эту категорию входят операторы выражения (например, присваивание а=б;), операторы возврата, управляющие выражения если, выключатель, пока, или же делать-пока операторы, и все три выражения в за утверждение.
  4. До того, как функция будет введена в вызов функции. Порядок, в котором оцениваются аргументы, не указан, но эта точка последовательности означает, что все их побочные эффекты завершаются до того, как функция будет введена. В выражении ж(я++) + грамм(j++) + час(k++), ж вызывается с параметром исходного значения я, но я увеличивается перед входом в тело ж. По аналогии, j и k обновляются перед вводом грамм и час соответственно. Однако не уточняется, в каком порядке ж(), грамм(), час() выполняются, ни в каком порядке я, j, k увеличиваются. Если тело ж обращается к переменным j и k, он может обнаружить, что оба, ни один из них или только один из них были увеличены. (Вызов функции ж(а,б,c) является нет использование оператора запятой; порядок оценки а, б, и c не указано.)
  5. При возврате функции после того, как возвращаемое значение копируется в вызывающий контекст. (Эта точка последовательности указана только в стандарте C ++; она присутствует только неявно в C.[7])
  6. В конце инициализатор; например, после оценки 5 в декларации int а = 5;.
  7. Между каждым декларатором в каждой последовательности деклараторов; например, между двумя оценками а++ в int Икс = а++, у = а++.[8] (Это нет пример оператора запятой.)
  8. После каждого преобразования, связанного со спецификатором формата ввода / вывода. Например, в выражении printf("фу% п% д", &а, 42), после % n оценивается и перед печатью 42.

Рекомендации

  1. ^ «ISO / IEC 14882: 2011». Получено 2012-07-04.
  2. ^ «Более тонкая альтернатива точкам последовательности (пересмотренная) (WG21 / N2239 J16 / 07-0099)». Получено 2012-07-05.
  3. ^ «Порядок оценки». Получено 2015-10-14.
  4. ^ Пункт 6.5 № 2 C99 Технические характеристики: "Между предыдущей и следующей точкой последовательности объект должен иметь свое сохраненное значение, измененное не более одного раза при оценке выражения. Кроме того, к предыдущему значению необходимо обращаться только для определения значения, которое необходимо сохранить."
  5. ^ Приложение C к C99 В спецификации перечислены обстоятельства, при которых можно предположить точку последовательности.
  6. ^ Стандарт C ++ 1998 года перечисляет точки последовательности для этого языка в разделе 1.9, параграфах 16–18.
  7. ^ Стандарт C ++, ISO 14882: 2003, раздел 1.9, сноска 11.
  8. ^ Стандарт C ++, ISO 14882: 2003, раздел 8.3: "Каждый инициализатор-декларатор в объявлении анализируется отдельно, как если бы он был сам по себе в объявлении."

внешняя ссылка