Подтвердить что ты не робот

Как работают префикс (++ x) и Postfix (x ++)?

Может ли кто-нибудь сказать мне, как работают префикс/постфиксные операторы? Я много искал онлайн, но ничего не нашел.

Из того, что я могу сказать prefex с первого раза, затем выполняет операцию, а затем назначает. Postfix сначала выполнит операцию, затем назначит и затем увеличит.

Но у меня проблемы с моим кодом:

int x, y;
x = 1;
y = x + x++; // (After operation y = 2)(x=2)

Однако, когда я это делаю:

y = x++ + x; // (After operation y = 3)(x=2)

Я не уверен, почему эти операции будут разными. У меня есть два вопроса:

  • Не могли бы вы объяснить разницу?

  • Как это относится к другому префиксу оператора?

4b9b3361

Ответ 1

  • В С# операнды + отображаются в порядке слева направо.
  • В C и С++ порядок оценки для операндов + не указан.

Для С# ваши примеры работают следующим образом:

 y = x + x++;
     ^ x is 1
         ^ x is increased to 2, but the postfix increment returns the old value (1)
 y = 2

 y = x++ + x;
     ^ x becomes 2, but postfix increment returns the old value (1)
           ^ x is now 2 here
 y = 3

Ответ 2

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

Для правильного анализа поведения С# см.

В чем разница между я ++ и ++ i?

Для С++ любое поведение является правильным поведением, в тех случаях, когда вы наблюдаете побочный эффект. С++ не определяет, когда видится побочный эффект приращения. Любые два компилятора могут сделать это по-другому.

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

Чтобы посмотреть на ваш конкретный случай:

int x, y;     
x = 1;     
y = x + x++; 

Вы сообщаете, что x и y равны 2. Это правильно в С#. В С# правильное поведение:

  • оценить y как переменную
  • оценивать x как значение - это 1
  • оцените значение x ++. Это оценивает x как переменную, затем берет исходное значение, равное 1, а затем увеличивает это значение, которое равно 2, затем присваивает значение 2 x, а затем выводит исходное значение, равное 1.
  • оцените 1 + 1, что составляет 2
  • назначить 2 на y.

Итак, x и y оба являются 2 в С#.

С++ может делать то же самое, но разрешено оценивать добавление в порядке справа налево. То есть, это разрешено делать:

  • оцените значение x ++. Это оценивает x как переменную, затем берет исходное значение, равное 1, а затем увеличивает это значение, которое равно 2, затем присваивает значение 2 x, а затем выводит исходное значение, равное 1.
  • оценивать x как значение - это 2
  • оцените 1 + 2, что составляет 3
  • оценить y как переменную
  • назначить 3 на y.

С++ также разрешено делать это:

  • оцените значение x ++. Это оценивает x как переменную, затем берет свое первоначальное значение, которое равно 1, а затем увеличивает это значение, которое здесь отсутствует...... и затем приводит к исходному значению, которое равно 1.
  • оценивать x как значение - это 1
  • оцените 1 + 1, что составляет 2
  • присваивает 2 x - этот шаг, который раньше отсутствовал.
  • оценить y как переменную
  • назначить 2 на y.

Итак, на С++ вы можете получить y как 3 или 2, в зависимости от прихоти писателя компилятора. В С# вы всегда получаете, что y равно 2. В С++ присваивание приращений может произойти в любое время, если это произойдет. В С# присвоение приращения должно происходить после вычисления инкрементного значения и перед использованием исходного значения. (При наблюдении из исполняемого потока, если вы пытаетесь наблюдать за этим материалом из другого потока или потоков, все ставки отключены.)

В вашем втором примере:

y = x++ + x; 

В С# требуется следующее поведение:

  • оценить y как переменную
  • оцените значение x ++. Это оценивает x как переменную, затем берет исходное значение, равное 1, а затем увеличивает это значение, которое равно 2, затем присваивает значение 2 x, а затем выводит исходное значение, равное 1.
  • оценивать x как значение - это 2
  • оцените 1 + 2, что составляет 3
  • назначить 3 на y.

Итак, правильный ответ в С# заключается в том, что y равно 3, а x равно 2.

Опять же, С++ может делать эти шаги в любом порядке. С++ разрешено делать:

  • оценивать x как значение - это 1
  • оцените значение x ++. Это оценивает x как переменную, затем берет исходное значение, равное 1, а затем увеличивает это значение, которое равно 2, затем присваивает значение 2 x, а затем выводит исходное значение, равное 1.
  • оцените 1 + 1, что составляет 2
  • оценить y как переменную
  • назначить 2 на y.

Опять же, в С++ правильный ответ заключается в том, что y равно 2 или 3, в зависимости от прихоти писателя компилятора. В С# правильный ответ заключается в том, что y равно 3.

Ответ 3

В обоих случаях приращение применялось после использования x. В первом случае он оценивался следующим образом: y = 1 + 1 (увеличивается на 2)

во втором

y = 1 (увеличивается на 2) + 2.

Вот почему вы получили разные ответы.

Ответ 4

В C и С++:
Вывод Не указано.

Ссылка - С++ 03 Стандарт:

Раздел 5: Выражения, Параграф 4:

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

В разделе C99 6.5.

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

Ответ 5

Выражения x++ и ++x имеют как результат (или значение), так и побочный эффект.

Если мы ограничим наше обсуждение интегральными типами операндов, результат x++ будет любым текущим значением x. Побочным эффектом является увеличение x на 1. Таким образом, учитывая код

x = 0;
y = x++;

результат будет x == 1 и y == 0 (предполагается, что x и y являются целыми типами).

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

x = 0;
y = ++x;

результат будет x == y == 1.

Что отличает C и С++ от С#, когда используются операнды и когда применяются побочные эффекты. С# гарантирует, что операнды в выражении всегда оцениваются слева направо. C и С++ гарантируют оценку слева направо для операторов &&, ||, ?:, comma и function-call () - для всех остальных операторов порядок, в котором оцениваются операнды, не указан,

Аналогично, в С#, побочные эффекты x++ и ++x будут применяться сразу после оценки выражения, тогда как C и С++ требуют, чтобы побочный эффект применялся до следующей точки последовательности.

Правила С# для оценки гарантируют корректность выражений типа x = x++, a = b++ * b++ и a[i] = i++, тогда как определения языка C и С++ явно говорят, что такие выражения приводят к поведению undefined (любой результат возможное).

Ответ 6

x + x ++ и x ++ + x - пример патологических случаев побочных эффектов, от которых вы не хотите зависеть. x ++ и ++ x оба приращения x, но при добавлении x порядок оценки undefined - компилятор может выбрать, с какой стороны он сначала оценивает.

Ответ 7

Рассмотрим:

y = x + x++;

Определено ли его поведение или нет (оно undefined в C и С++, очевидно, оно хорошо определено на С#), независимо от того, что вы пытаетесь сделать, там должен быть лучший способ выразить это.

Если вы принимаете строгую оценку слева направо, то вышеуказанное может быть записано как:

y = x * 2;
x ++;

Значение ясно и недвусмысленно для любого читателя, который знает, что означают =, * и ++, и у будущих сопровождающих вашего кода не будет соблазна выследить вас.

Или вы могли бы написать x + x или x << 1, если вы не доверяете компилятору генерировать эффективный код, но такое недоверие обычно неуместно.

Если вы настаиваете, вы даже можете написать:

y = x++ * 2;

Это немного красноречиво для моих личных вкусов, но это все еще недвусмысленно.

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