Непонятный результат вычисления

191
25 апреля 2017, 05:02

Почему в данном случае a будет равно 20, а не 21?

int a = 10;
a += a++;
Console.WriteLine(a);
Answer 1

Это вариация классической задачи про ++i + ++i в несколько упрощенном варианте.

В C++ - это undefined behavior, и результатом в большинстве компиляторов будет 21. Цитируя lurkmore:

согласно стандартам С и С++, побочные эффекты (то есть инкремент в данном случае) могут быть применены в любой удобный для компилятора момент между двумя точками следования. Конструкцию i = ++i + ++i; компилятор вправе понять и как

tmp=i; tmp++; i = tmp; tmp++; i += tmp;

и как

tmp=i; tmp++; tmp++; i = tmp + tmp;

Из-за непредсказуемости поведения этот пример раньше часто предлагали объяснить на собеседованиях :)

В C# результатом будет 20, т.к. порядок вычисления явно задан спецификацией. В C# нет никаких точек следования, компилятор не настолько свободен при оптимизации выражений, так что он вычисляет в том порядке, в котором ему приказали:

+= - это compound assignment operator. Он не самостоятельный оператор (не допускает отдельной перегрузки, и т.д.), а просто шорткат для

a = a + a++;

Т.е. он просто берет результат вычисления a (10), прибавляет к нему результат вычисления a++ (10) и складывает сумму (20) обратно в a. При этом операнды вычисляются именно слева направо.

Процесс вычисления постфиксного оператора a++ описан в спецификации C#, 7.6.9 Postfix increment and decrement operators, и он следующий:

  • Сохраняется текущее значение a. (10)
  • Вызывается оператор (++) с передачей сохраненного значения a в качестве аргумента.
  • Результат вычисления оператора (11) сохраняется в a. (которое позже перезатрется результатом сложения)
  • Сохраненное значение a возвращается как результат операции. (10)

Поэтому

a + (a++) -> 20
(a++) + a -> 21
Answer 2

Значение присвоения оператора инкремента не используется ни в одном из путей выполнения, что-то похожее скажет ReSharper на такой код a += a++; сообщение:

Value assigned is not used in any execution path

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

int a = 10;
a += ++a;
Console.WriteLine(a);

Так как операция префиксного инкремента выполнится раньше, чем выполнится сложение и присваивание.

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

Ссылки:

  • Оператор ++ (справочник по C#)
  • Оператор -- (Справочник по C#)
Answer 3
a += a++;
^---------- 10
     ^----- 10
      ^^--- 11
     ^^^--- значение 10, но a=11
  ^^------- 10+10 = 20
Answer 4

Я не совсем согласен с тем, как обьяснили другие ответчики.

Для начала:

инкремент = увеличить (обычно на 1)

Пре- = изменить переменную ПЕРЕД использованием

Пост- = увеличить переменную ПОСЛЕ использования

Код

int a = 10;
a += a++;

по логике должен быть 21.

Вполне логично что должна быть последовательность действий

  1. а присвоить 10 (инициализация)
  2. используем а (считываем значение 10) и инкрементируем в 11
  3. 11(до знака присвоения) + 10(после знака присвоения) = 21

Скорее всего на других языках значение будет колебатся между 20 и 21 в зависимости от конкретного языка на котором будешь тестировать(считай, в зависимости от компилятора)

Почему я так думаю? Есть очень интересный пример

int i = 5;
i = ++i + ++i;

ожидаемое число -- 14. Потому, что правильная последовательность действий будет

  1. i = 5 (инициализация)
  2. i = 6
  3. i = 7(это ведь преинкремент! Все преинкременты должны исполнятся до знака присвоения!)
  4. i = 7+7

но на практике, разные компиляторы разных языков будут выдавать разные значения в рамках от 10 до 14 в зависимости от компилятора. Результат компилирования в:

  • C#: 13
  • Java: 13
  • C и С++ : 13 и 14 в зависимости от компилятора
  • Perl: 14
  • Pawn: 13
  • PHP: 13
  • JS: 13
  • VB: 10
  • Другие языки легко нагуглить.

Потому мой ответ: Это специфика работы компилятора/специфика языка по его спецификации(если там указано)

[ в случае С# указано ]

READ ALSO
Правильная остановка/запуск службы windows

Правильная остановка/запуск службы windows

Нашёл на просторах интернета такой код:

292
Передать аргумент из класса в форму

Передать аргумент из класса в форму

Использую метод invoke action в форме работает отменно)

243
Не могу подключить Bootstrap

Не могу подключить Bootstrap

Bootstrap подключается только по адресу localhost/site/ , если вести localhost/site/index/index (это одна и та самая страница )то работать уже не будетПолучатся что...

303
Создание меток программно

Создание меток программно

Допустим имеется массив меток:

223