языковой адвокат — ++ x% = 10 хорошо определены в C ++?

Просматривая код какого-то проекта, я наткнулся на следующее утверждение:

++x %= 10;

Это утверждение хорошо определено в C ++ или оно относится к той же категории, что и

a[i] = i++

?

56

Решение

Согласно C ++ 11 1.9 Program execution /15:

За исключением отмеченных случаев, оценки операндов отдельных операторов и подвыражений отдельных выражений не являются последовательными.

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

В этом случае я считаю ++x является побочным эффектом и x %= 10 это вычисление значения, поэтому вы могли бы подумать, что это будет неопределенное поведение. Тем не менее назначение раздел (5.17 /1) имеет это сказать (мой жирный):

Во всех случаях назначение является последовательным после вычисления значения правого и левого операндов, и до вычисления значения выражения присваивания.

Следовательно, это означает, что обе стороны располагаются в последовательности перед назначением и перед тем, как результат назначения становится доступным. И так как стандарт также гласит (5.17 /7) тот x OP = y идентично x = x OP y но с x получается только один раз, получается является четко определенное поведение, так как оно эквивалентно:

++x = Q % 10; // where Q is the value from ++x, not evaluated again.

Остается только один вопрос: боковая сторона задания оценивается с они не упорядочено. Тем не менее, я не думаю, что это имеет значение в этом случае, поскольку оба они будут иметь одинаковый эффект:

++x = Q % 10; // LHS evaluated first
Q = ++x % 10; // RHS evaluated first

Теперь это мой чтение стандарта. Хотя у меня достаточно опыта в расшифровке сложных документов, может что-то, что я пропустил — я так не думаю, потому что мы все здесь провели оживленную дискуссию, чтобы добраться до этой точки :-), и я думаю, что мы все создали соответствующие разделы.

Но, независимо от того, хорошо ли это определено, достойные кодеры не должен писать код, как это. Прошло много времени с тех пор, когда PDP-минималисты занимали мало памяти и занимали мало места, нам пора написать наш код удобочитаемый.

Если вы хотите увеличить, возьмите по модулю, используйте x = (x + 1) % 10Чтобы облегчить понимание следующего бедного Джо, читающего этот код.

63

Другие решения

TL; DR: Это четко определено, потому что x гарантированно увеличивается до назначения.


Немного стандартного C ++ 11

[Intro.execution] / 15:

Кроме отмеченных, оценки операндов отдельных операторов
и подвыражений отдельных выражений не упорядочены.

Тем не менее, [expr.ass] / 1 замечает что-то:

Во всех случаях присваивание последовательности после вычисления значения
правого и левого операндов
, и до вычисления значения
выражение присваивания.

Так что это составляет исключение из первой цитаты. Более того, как указано в [expr.pre.incr]1, ++x эквивалентно x += 1, что также охватывается приведенной выше цитатой: присваивание выполняется до вычисления значения. таким образом за ++x приращение секвенируется до вычисления значения.

Принимая это во внимание, нетрудно видеть, что в ++x %= 10инкремент выполняется до назначения.
Таким образом, побочный эффект приращения секвенируется перед побочным эффектом назначения, и, таким образом, все вовлеченные побочные эффекты чередуются.

Иными словами, стандарт устанавливает следующую последовательность:

  • ++x а также 10 оцениваются — порядок которых не упорядочен, но 10 это просто буквальный, так что это не имеет значения здесь.
    • ++x оценивается:
      • Во-первых, значение x увеличивается
      • Затем выполняется вычисление значения, и мы получаем lvalue, ссылаясь на x,
  • Задание выполнено. Обновленное значение x берется по модулю 10 и назначен x,
  • Может последовать вычисление значения присваивания, которое четко упорядочено после присваивания.

следовательно

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

не применяется как побочные эффекты и значения вычисляются последовательно.


1 Не [expr.post.incr], который был бы для приращения постфикса!

22

Давайте посмотрим на унарный оператор приращения:

5.3.2 Увеличение и уменьшение [expr.pre.incr]

1 операнд префикса ++ изменяется путем добавления 1 или устанавливается на true если это bool (это использование устарело). Операндом должно быть изменяемое значение l. Тип операнда должен быть арифметическим типом или указателем на полностью определенный тип объекта. Результатом является обновленный операнд; это lvalue, и это битовое поле, если операнд является битовым полем. Если x не тип bool, выражение ++x эквивалентно x+=1,
[…]

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

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

20

Я собираюсь предложить альтернативный ответ, не цитируя хорошую книгу, так как думаю, что ее переписывание слегка делает это очевидным.

++x %= 10;       // as stated
x += 1 %= 10;    // re-write the 'sugared' ++x

Это достаточно ясно в моих глазах. Как мы знаем, результат присваивания (который, если мы действительно хотим, все еще «засахаренный» += сводится к) само по себе является lvalue, поэтому не должно быть никаких сомнений в том, что при дальнейшем сокращении выражение будет:

(x = x+1) %= 10  // += -> =1+
x = (x+1) % 10   // assignment returns reference to incremented x
5

В выражении

++x %= 10;

самая запутанная часть в том, что x изменяет дважды между двумя точками последовательности, один раз по префиксу ++ и один раз по присваиванию результата. Создается впечатление, что вышеприведенное выражение вызывает неопределенное поведение, как мы узнали в старом C ++, что

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

В C ++ 11 правило другое (речь идет о последовательность действий вместо последовательность точек!):

Если побочный эффект на скалярном объекте unsequenced относительно другого побочного эффекта на тот же скалярный объект или вычисления значения, используя значение того же скалярного объекта, поведение не определено.

Как мы уже знаем, что ++x Вышеуказанное выражение будет оцениваться только один раз (и даст lvalue), потому что

С ++ 11: 5.17

Поведение выражения формы E1 op = E2 эквивалентно E1 = E1 op E2 Кроме этого E1 оценивается только один раз.

а также знаю, что оценка операндов ++x а также 10 будет иметь место до вычисления результата %= оператор по стандарту:

Вычисления значений операндов оператора секвенируются до вычисления значения результата оператора.

Заключение:

++x будет оцениваться только один раз, давая lvalue и только после этого %= операция будет выполнена.
Это означает, что обе модификации x последовательность и приведенное выше выражение хорошо определено.

5

Ну это определенный. Как неопределенное поведение:

§1.9 / 15:
Если побочный эффект на скалярный объект не секвенирован относительно другого побочного эффекта на тот же скалярный объект или вычисления значения с использованием значения того же скалярного объекта, поведение не определено.

Здесь есть два непоследовательных побочных эффекта.

Учитывая выражение ++x %= 10; двигаясь слева направо, имеем:

  1. расчет стоимости (x+1)
  2. изменение объекта ( =, как в x = x + 1), например побочный эффект согласно §1.9 / 12
  3. неопределенно последовательность операция (%=) что само по себе имеет значение вычисления (‘%‘) и объект-модификация побочный эффект=‘) (там же с 1,2) на тот же скалярный объектx«).

Два подвыражения в полном выражении не являются последовательными по отношению друг к другу. Хотя мы начали с чтения слева направо, это неопределенно последовательность, так что явно нет частичной упорядоченной помощи из §1.9 / 13:

Учитывая любые две оценки а также В, если последовательность перед В, затем исполнение должно предшествовать исполнению В. Если не секвенируется раньше В а также В не секвенируется раньше , затем а также В являются unsequenced.

Итак, УДБ.

4

Приращение префикса (++ x) имеет наивысший приоритет при присваивании модуля (% =). Утверждение: ++ x% = 10; может быть выражено как:

++x;
x%= 10;
1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector