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

Я читал K&R и наткнулся на этот пример о неопределенности в поведении при оценке выражения вроде a[i]=i++; Спецификация C99 в $ 6.5.2 говорит, что

Между предыдущей и следующей точкой последовательности сохраненное значение объекта должно быть изменено не более одного раза путем вычисления выражения. Кроме того, предыдущее значение должно считываться только для определения сохраняемого значения.

Приведенный выше пример от K&R подходит для первого утверждения. Пожалуйста, объясните, как это не удается на втором.

Говорит ли стандарт что-нибудь о порядке оценки подвыражений в случае задействования точек последовательности. Например. a[i++] || b[i++]. Я знаю, что они оцениваются слева направо, но как это можно вывести из приведенного выше утверждения или где-то это явно указано в стандарте?


person Bazooka    schedule 30.01.2012    source источник
comment
возможный дубликат неопределенного поведения и точек последовательности   -  person Lundin    schedule 30.01.2012
comment
@undur_gongor Насколько мне известно, между C и C++ нет разницы, когда речь идет о точках последовательности и порядке оценки.   -  person Lundin    schedule 30.01.2012
comment
@Lundin Спасибо за замечательную ссылку.   -  person Bazooka    schedule 30.01.2012
comment
@Lundin: Тогда это может быть частью хорошего ответа. Тем не менее, вопрос не является дубликатом.   -  person undur_gongor    schedule 30.01.2012
comment
@undur_gongor О, пожалуйста, мы получаем как минимум пять i+++++i вопросов в неделю. Что касается конкретного случая, почему оператор присваивания не является точкой последовательности, кто-то также связал это сообщение.   -  person Lundin    schedule 30.01.2012
comment
stackoverflow.com/questions/949433 может быть самым большим членом этого кластера дубликатов, ориентированным на C.   -  person Steve Jessop    schedule 16.04.2013


Ответы (2)


Говорит ли стандарт что-нибудь о порядке оценки подвыражений в случае точек последовательности?

Порядок оценки хорошо определен в случае условных операторов &&, а также ||, и это та самая причина, по которой работает короткое замыкание.

Это явно указано в стандарте c99.

Ссылка: стандарт c99

Приложение J: J.1 Неопределенное поведение

1 Не указано следующее:
.....

Порядок, в котором вычисляются подвыражения, и порядок, в котором имеют место побочные эффекты, за исключением случаев, указанных для вызова функции (), &&, ||, ?: и операторов запятой (6.5).
.... .

Далее,
6.5.14 Логический оператор ИЛИ

4) В отличие от побитового | оператор || оператор гарантирует оценку слева направо; есть точка последовательности после оценки первого операнда. Если первый операнд не равен 0, второй операнд не оценивается.

А также для логического И:

6.5.13 Логический оператор И

В отличие от побитового двоичного оператора &, оператор && гарантирует вычисление слева направо; если оценивается второй операнд, между оценками первого и второго операндов есть точка последовательности. Если первый операнд сравнивается равным 0, второй операнд не оценивается.

person Alok Save    schedule 30.01.2012
comment
Спасибо, но не могли бы вы пояснить первый вопрос, который я задал о [i]=i++; - person Bazooka; 30.01.2012
comment
Оператор присваивания @Parminder не является точкой последовательности в C. Примечание. C++11 вводит понятие последовательности до/после, а [i]=i++ — это хорошо определен в C++11. См. также stackoverflow.com/questions/4362501/ - person Suma; 30.01.2012
comment
ЗАМЕЧАТЕЛЬНЫЙ ОТВЕТ! Это помогло мне с a || b++ && c узнать, всегда ли оценивается b++. Это не так, но более высокий приоритет оператора && вызовет аргументы у многих людей, утверждающих обратное. - person Kevin P. Rice; 16.07.2012

По первой части вопроса:

Предложение применяется к объектам, изменяемым выражением, то есть ia[i]). Таким образом, предыдущее значение i должно использоваться исключительно для определения «нового» значения для i.

Но выражение «использует» его также для определения элемента массива, в который будет производиться запись.

Предыстория заключается в том, что в противном случае было бы неясно, обозначает ли i значение i до или после приращения.

person undur_gongor    schedule 30.01.2012
comment
Спасибо, но у меня есть еще одно сомнение в отношении этого. Выражение вроде ++i==i на первый взгляд кажется двусмысленным. Но он не пытается ничего изменить, кроме i. Так это тоже неопределенное поведение?? - person Bazooka; 30.01.2012
comment
Я не пытаюсь изменить какое-либо lvalue. Все, что я пытаюсь сказать, это то, что при оценке справа налево я меняю i только один раз, и когда я получаю доступ к i во второй раз, я делаю это, чтобы изменить значение самого i. Это подтверждает второе утверждение, которое я думаю. Так в чем проблема ? Является ли это законным выражением с определенным поведением? - person Bazooka; 30.01.2012
comment
Переназначения не происходит, только операция приращения. Это ==, а не =, на случай, если вы пропустили. - person Bazooka; 30.01.2012
comment
Извините, я, должно быть, слепой. Но тогда вы используете значение изменяемого объекта i не только для вычисления нового значения i, но и для сравнения. Таким образом, вы нарушаете то же самое ограничение, что и в вашем вопросе. - person undur_gongor; 30.01.2012
comment
я думаю, что я понял я сейчас. Выражение не определено, потому что Any access to an object that is being modified between two sequence points should be to change that object only and nothing else. В этом примере мы используем его для сравнения, которое нарушает второе правило. Но он по-прежнему остается в силе в первом утверждении. Ваше здоровье !! - person Bazooka; 30.01.2012