Точка последовательности - Sequence point
А точка последовательности определяет любую точку в компьютерная программа с исполнение при котором гарантируется, что все побочные эффекты предыдущих оценок, и никаких побочных эффектов от последующих оценок еще не было. Они часто упоминаются со ссылкой на C и C ++, потому что они являются основной концепцией для определения достоверности и, если они допустимы, возможных результатов выражений. Иногда необходимо добавить дополнительные точки последовательности, чтобы сделать выражение определенным и гарантировать единый допустимый порядок оценки.
С C ++ 11, термин «точка последовательности» заменен на «последовательность». Есть три возможности:[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 ++ перегруженные операторы действуют как функции, и поэтому операторы, которые были перегружены, вводят точки последовательности так же, как вызовы функций.)
- Между вычислением левого и правого операндов && (логическое И ), || (логическое ИЛИ ) (как часть оценка короткого замыкания ), и операторы запятой. Например, в выражении
*п++ != 0 && *q++ != 0, все побочные эффекты подвыражения*п++ != 0завершаются до любой попытки доступаq. - Между вычислением первого операнда троичного оператор "вопросительный знак" и второй или третий операнд. Например, в выражении
а = (*п++) ? (*п++) : 0после первого*п++, что означает, что он уже был увеличен к моменту выполнения второго экземпляра. - В конце полного выражения. В эту категорию входят операторы выражения (например, присваивание
а=б;), операторы возврата, управляющие выраженияесли,выключатель,пока, или жеделать-покаоператоры, и все три выражения взаутверждение. - До того, как функция будет введена в вызов функции. Порядок, в котором оцениваются аргументы, не указан, но эта точка последовательности означает, что все их побочные эффекты завершаются до того, как функция будет введена. В выражении
ж(я++) + грамм(j++) + час(k++),жвызывается с параметром исходного значенияя, нояувеличивается перед входом в телож. По аналогии,jиkобновляются перед вводомграммичассоответственно. Однако не уточняется, в каком порядкеж(),грамм(),час()выполняются, ни в каком порядкея,j,kувеличиваются. Если теложобращается к переменнымjиk, он может обнаружить, что оба, ни один из них или только один из них были увеличены. (Вызов функцииж(а,б,c)является нет использование оператора запятой; порядок оценкиа,б, иcне указано.) - При возврате функции после того, как возвращаемое значение копируется в вызывающий контекст. (Эта точка последовательности указана только в стандарте C ++; она присутствует только неявно в C.[7])
- В конце инициализатор; например, после оценки
5в декларацииint а = 5;. - Между каждым декларатором в каждой последовательности деклараторов; например, между двумя оценками
а++вint Икс = а++, у = а++.[8] (Это нет пример оператора запятой.) - После каждого преобразования, связанного со спецификатором формата ввода / вывода. Например, в выражении
printf("фу% п% д", &а, 42), после% nоценивается и перед печатью42.
Рекомендации
- ^ «ISO / IEC 14882: 2011». Получено 2012-07-04.
- ^ «Более тонкая альтернатива точкам последовательности (пересмотренная) (WG21 / N2239 J16 / 07-0099)». Получено 2012-07-05.
- ^ «Порядок оценки». Получено 2015-10-14.
- ^ Пункт 6.5 № 2 C99 Технические характеристики: "Между предыдущей и следующей точкой последовательности объект должен иметь свое сохраненное значение, измененное не более одного раза при оценке выражения. Кроме того, к предыдущему значению необходимо обращаться только для определения значения, которое необходимо сохранить."
- ^ Приложение C к C99 В спецификации перечислены обстоятельства, при которых можно предположить точку последовательности.
- ^ Стандарт C ++ 1998 года перечисляет точки последовательности для этого языка в разделе 1.9, параграфах 16–18.
- ^ Стандарт C ++, ISO 14882: 2003, раздел 1.9, сноска 11.
- ^ Стандарт C ++, ISO 14882: 2003, раздел 8.3: "Каждый инициализатор-декларатор в объявлении анализируется отдельно, как если бы он был сам по себе в объявлении."
внешняя ссылка
- Вопрос 3.8 FAQ для comp.lang.c