Очки последовательности и частичный порядок

c++ c expression language-lawyer

1668 просмотра

4 ответа

73436 Репутация автора

Несколько дней назад было обсуждение здесь о том, является ли выражение

я = ++ я + 1

вызывает UB (неопределенное поведение) или нет.

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

Я был вовлечен в дискуссию с Йоханнесом Шаубом в той же теме. Согласно ему

i = (i, i ++, i) +1 ------ (1) / * также вызывает UB * /

Я сказал, что (1) не вызывает UB, потому что побочные эффекты предыдущих подвыражений очищаются оператором запятой ',' между i и i ++ и между i ++ и i.

Затем он дал следующее объяснение:

«Да, точка последовательности после i ++ завершает все побочные эффекты до него, но ничто не останавливает побочный эффект присваивания, перекрывающийся с побочным эффектом i ++. Основная проблема заключается в том, что побочный эффект присваивания не указан после или до оценки обоих операндов присваивания, и поэтому точки последовательности не могут ничего сделать для защиты этого: точки последовательности вызывают частичный порядок: только потому, что после и до i ++ есть точка последовательности, не означает, что все побочные эффекты секвенированы в отношении я .

Также обратите внимание, что просто точка последовательности ничего не значит: порядок вычислений не определяется формой кода. Это продиктовано семантическими правилами. В этом случае не существует семантического правила, согласно которому возникает побочный эффект присваивания в отношении оценки обоих его операндов или подвыражений этих операндов ".

Заявление, написанное «жирным шрифтом», смутило меня. Насколько мне известно:

«В определенных указанных точках в последовательности выполнения, называемых точками последовательности, все побочные эффекты предыдущих оценок должны быть завершены, и никаких побочных эффектов последующих оценок не должно быть».

Так как операторы запятой также задают порядок выполнения, побочный эффект i ++ был отменен, когда мы достигли последнего i.He (Йоханнес) был бы прав, если бы порядок вычисления не был указан (но в случае оператора запятой он хорошо указан ).

Так что я просто хочу знать, вызывает ли (1) UB или нет? Может кто-нибудь дать другое веское объяснение?

Спасибо!

Автор: Prasoon Saurav Источник Размещён: 13.12.2009 08:29

Ответы (4)


15 плюса

292879 Репутация автора

Решение

Стандарт C говорит об операторах присваивания (C90 6.3.16 или C99 6.5.16 операторы присваивания):

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

Мне кажется, что в заявлении:

i=(i,i++,i)+1;

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

Тем не менее, это выражение:

*(some_ptr + i) = (i,i++,i)+1;

будет иметь неопределенное поведение, потому что порядок вычисления 2 операндов оператора присваивания не определен, и в этом случае вместо проблемы, когда имеет место побочный эффект оператора присваивания, проблема в том, что вы не знаете, является ли значение Я использовал в операнде левой ручки будет оцениваться до или после правой части. Эта проблема оценки порядка не возникает в первом примере, потому что в этом выражении значение iфактически не используется в левой части - все, что интересует оператор присваивания, это "lvalue-ness" of i.

Но я также думаю, что все это достаточно схематично (и мое понимание нюансов достаточно поверхностно), и я не удивлюсь, если кто-то сможет убедить меня в обратном (в любом случае).

Автор: Michael Burr Размещён: 13.12.2009 08:52

6 плюса

558674 Репутация автора

Я считаю, что следующее выражение определенно имеет неопределенное поведение.

i + ((i, i++, i) + 1)

Причина в том, что оператор запятой указывает точки последовательности между подвыражениями в скобках, но не указывает, где в этой последовательности происходит вычисление левого операнда +. Одна возможность существует между окружающими точками последовательности, i++и это нарушает 5/4, как iзаписано между двумя точками последовательности, но также дважды считывается между одними и теми же точками последовательности, и не только для определения значения, которое нужно сохранить, но и для определения значения первый операнд к +оператору.

Это также имеет неопределенное поведение.

i += (i, i++, i) + 1;

Теперь я не уверен в этом утверждении.

i = (i, i++, i) + 1;

Хотя применяются те же принципы, они iдолжны «оцениваться» как модифицируемое lvalue и могут быть выполнены в любое время, но я не уверен, что его значение когда-либо читается как часть этого. (Или есть другое ограничение, которое выражение нарушает, чтобы вызвать UB?)

Подвыражение (i, i++, i)происходит как часть определения значения, которое будет сохранено, и это подвыражение содержит точку последовательности после сохранения значения до i. Я не вижу способа, чтобы это не потребовало завершения побочного эффекта i++до определения значения, которое будет сохранено, и, следовательно, как можно более раннего момента возникновения побочного эффекта назначения.

После этой точки секвенции iзначение читается не более одного раза и только для определения значения, которое будет сохранено обратно i, так что с этой последней частью все в порядке.

Автор: CB Bailey Размещён: 13.12.2009 10:30

-1 плюса

73436 Репутация автора

Я был смущен в начале относительно заявления Йоханнеса (Литб), но он упомянул это в:

i = (i, ++i, i) +1


Если является присваиванием и является приращением. :s:точка последовательности, то побочные эффекты могут быть упорядочены следующим образом между точками последовательности: (i :s: i++< a ><n> :s: i) + 1. Здесь значение скаляра iменялось дважды между первой и второй точкой последовательности. Порядок, в котором происходит присваивание и приращение, не определен, и, поскольку между ними нет точки последовательности, она даже не атомарна по отношению друг к другу. Это разрешенный порядок, разрешенный неопределенным порядком этих побочных эффектов.

Это отличается от того (i++, i++), что порядок оценки двух подвыражений находится слева направо, и в точке последовательности между ними приращение предыдущей оценки должно быть завершено, а следующее приращение еще не произошло. Это обеспечивает отсутствие изменения значения iмежду двумя точками последовательности, что делает (i++, i++)действительным

Это заставило меня думать, что последовательность, упомянутая litb, недействительна, потому что согласно C99:

6.5.16.1 (2) В простом присваивании (=) значение правого операнда преобразуется в тип выражения присваивания и заменяет значение, хранящееся в объекте, обозначенном левым операндом.

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

6.5.17 (2) Левый операнд оператора запятой оценивается как пустое выражение; после его оценки есть точка последовательности. Затем вычисляется правый операнд; результат имеет свой тип и значение.

т.е. самый правый операнд операции с запятой должен быть оценен, чтобы узнать значение и тип выражения запятой (и значение правого операнда для моего примера).

Таким образом, в этом случае «предыдущая точка последовательности» для побочного эффекта присваивания будет, по сути, самой правой запятой операцией. Возможная последовательность, упомянутая Йоханнесом, неверна.

Пожалуйста, поправьте меня, если я ошибаюсь.


Автор: Prasoon Saurav Размещён: 14.12.2009 03:00

5 плюса

31558 Репутация автора

i=(i,i++,i)+1 ------ (1) /* invokes UB as well */

Это не вызывает неопределенное поведение. Побочный эффект i++будет иметь место перед оценкой следующей точки последовательности, которая обозначается запятой после нее, а также перед присвоением.

Хороший язык судоку, хотя. :-)

править: Там более сложное объяснение здесь .

Автор: Michael Foukarakis Размещён: 14.12.2009 08:29
Вопросы из категории :
32x32