Точка последовательности - Sequence point
Точка последовательности определяет любую точку в компьютерной программе «s исполнение , при котором гарантируется , что все побочные эффекты предыдущих оценок будет выполнена, и никаких побочных эффектов от последующих оценок до сих пор не выполнено. Они часто упоминаются со ссылкой на C и C ++ , потому что они являются основной концепцией для определения достоверности и, если они допустимы, возможных результатов выражений. Иногда необходимо добавить дополнительные точки последовательности, чтобы сделать выражение определенным и гарантировать единый допустимый порядок оценки.
В C ++ 11 термин «точка последовательности» был заменен последовательностью. Есть три возможности:
- Оценка экспрессионная может быть секвенирована до того, что другого выражения, или , что эквивалентно оценка в другом выражении является секвенировала после того, что из первых.
- Вычисление выражений имеет неопределенную последовательность, что означает , что одно из них следует за другим, но не определено.
- Оценка выражений не упорядочена.
Выполнение неупорядоченных оценок может перекрываться с катастрофическим неопределенным поведением, если они разделяют состояние . Эта ситуация может возникнуть при параллельных вычислениях , вызывая состояние гонки . Однако это может уже возникнуть в простых несовпадающих ситуациях, например (a = 1) + (b = a)
, когда часть присвоения a
(например, половина битов) может произойти раньше b = a
, а остальная часть после этого, так что после оценки выражения b
может содержаться бессмысленное промежуточное звено. состояние a
.
Примеры двусмысленности
Рассмотрим две функции f()
и g()
. В C и C ++ +
оператор не связан с точкой последовательности, и поэтому в выражении f()+g()
возможно, что сначала будет выполнено либо, f()
либо g()
. Оператор запятая вводит точку последовательности, и поэтому в коде f(),g()
определен порядок оценки: сначала f()
вызывается, а затем g()
вызывается.
Точки последовательности также вступают в игру, когда одна и та же переменная изменяется более одного раза в одном выражении. Часто цитируемым примером является выражение Ci=i++
, которое, по-видимому, одновременно присваивает i
свое предыдущее значение и увеличивает его i
. Конечное значение i
неоднозначно, потому что, в зависимости от порядка вычисления выражения, приращение может происходить до, после или чередоваться с присваиванием. Определение конкретного языка может указывать одно из возможных поведений или просто говорить, что поведение не определено . В C и C ++ оценка такого выражения приводит к неопределенному поведению. Другие языки, такие как C # , определяют приоритет оператора присваивания и приращения таким образом, чтобы i=i++
гарантировать результат выражения .
Точки последовательности в C и C ++
В C и C ++ точки следования встречаются в следующих местах. (В C ++ перегруженные операторы действуют как функции, и поэтому операторы, которые были перегружены, вводят точки последовательности так же, как вызовы функций.)
- Между вычислением левого и правого операндов && ( логическое И ), || ( логическое ИЛИ ) (как часть оценки короткого замыкания ) и операторы запятой . Например, в выражении все побочные эффекты подвыражения завершаются до любой попытки доступа .
*p++ != 0 && *q++ != 0
*p++ != 0
q
- Между вычислением первого операнда тернарного оператора «вопросительный знак» и второго или третьего операнда. Например, в выражении есть точка последовательности после первой , что означает, что она уже была увеличена к моменту выполнения второго экземпляра.
a = (*p++) ? (*p++) : 0
*p++
- В конце полного выражения. Эта категория включает в себя операторы выражения (например, задание ), возвращаемое значение , управляющие выражениями , , , или - заявления, и все три выражения в заявлении.
a=b;
if
switch
while
do
while
for
- До того, как функция будет введена в вызов функции. Порядок, в котором оцениваются аргументы, не указан, но эта точка последовательности означает, что все их побочные эффекты завершаются до того, как функция будет введена. В выражении , вызывается с параметром исходного значения , но увеличивается перед входом в корпус . Аналогичным образом , и обновляются перед входом и соответственно. Однако, это не указано , в каком порядке , , выполняются, и в каком порядке , , увеличиваются. Если тело обращается к переменным и , он может обнаружить, что оба, ни одна из них или только одна из них были увеличены. (Вызов функции является не вариант использования оператора запятой; порядок вычисления для , и не определен.)
f(i++) + g(j++) + h(k++)
f
i
i
f
j
k
g
h
f()
g()
h()
i
j
k
f
j
k
f(a,b,c)
a
b
c
- При возврате функции после того, как возвращаемое значение копируется в вызывающий контекст. (Эта точка последовательности указана только в стандарте C ++; она присутствует только неявно в C.)
- В конце инициализатора ; например, после оценки
5
в объявлении .int a = 5;
- Между каждым декларатором в каждой последовательности деклараторов; например, между двумя оценками in . (Это не пример оператора запятой.)
a++
int x = a++, y = a++
- После каждого преобразования, связанного со спецификатором формата ввода / вывода. Например, в выражении есть точка следования после оценки и перед печатью .
printf("foo %n %d", &a, 42)
%n
42
использованная литература
- ^ «ISO / IEC 14882: 2011» . Проверено 4 июля 2012 .
- ^ «Более детальная альтернатива точкам последовательности (пересмотренная) (WG21 / N2239 J16 / 07-0099)» . Проверено 5 июля 2012 .
- ^ «Порядок оценки» . Проверено 14 октября 2015 .
- ^ Пункт 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