x += x++

в 20:00, , рубрики: .net, ошибки программистов

Хотел бы начать перевод с маленького опроса. Вопрос к .NET разработчикам пишущим на языке программирования C#.

Опрос в конце перевода.

Сегодня я смотрел внутренний список разработчиков языка C#. Один из вопросов был о поведении выражения «x += x++», а именно, каким должно быть правильное поведение. Я думаю этот вопрос более чем интересный, поэтому решил посвятить ему запись в своем блоге. Но для начала, НИКОГДА НЕ ПИШИТЕ ТАКОЙ КОД.

ОК, мы можем начать…

Используем следующий код для примера:

int x = 3;
x += x++;

Первое, что делает компилятор, когда видит код z += y это преобразует его в z = z + y. Это, очевидно верно, для операторов +=, -=, *=, /=.

ОК, это было просто. Теперь, мы можем просто посчитать значение такого выражения:

x = x + x++;

Этот код дает такой же результат, что и код:

x = x + x;

Однако, он дает различный результат с кодом:

x = x++ + x;

который в свою очередь дает одинаковый результат с кодом:

x = x + ++x;

Как бы такое поведение не сводило вас с ума, оно действительно имеет место быть. Но для начала ответим на вопрос: какая разница между x++ и ++x? x++ возвращает значение x текущему выражению, а затем увеличивает его на единицу. ++x увеличивает значение x на единицу и затем возвращает увеличенное значение текущему выражению. Принимая во внимание вышесказанное (и учитывая, что C# обрабатывает выражения слева на право), мы можем понять, почему предыдущий код работает именно так.

int x = 3;
x = x + x++;

Компилятор будет подсчитывать это выражение следующим образом:

  1. x = (x) + x++ -> первый x подсчитывается и возвращает значение 3, x = 3;
  2. x = 3 + (x)++ -> x подсчитывается и возвращает 3, x = 3;
  3. x = 3 + (x++) -> x++ возвращает значение 3 и x увеличивается на единицу, x = 4;
  4. x = (3 + 3) -> выражение 3 + 3 подсчитывается и возвращает 6, x = 4;
  5. (x = 6) -> x присваивается значение 6 (переписывая предыдущее значение 4).

Теперь посмотрим, что будет в результате такого кода:

int x = 3;
x = x++ + x;

  1. x = (x)++ + x -> x подсчитывается и возвращает значение 3, x = 3;
  2. x = (x++) + x -> x++ возвращает значение 3 и x увеличивается на единицу, x = 4;
  3. x = 3 + (x) -> x подсчитывается и возвращает значение 4, x = 4;
  4. x = 3 + 4 -> выражение 3 + 4 подсчитывается и возвращает значение 7, x = 4;
  5. (x = 7) -> x присваивается значение 7 (переписывая предыдущее значение 4).

Теперь рассмотрим такой код:

int x = 3;
x = x + ++x;

  1. x = (x) + ++x -> первый x подсчитывается и возвращает значение 3, x = 3;
  2. x = 3 + (++x) -> ++x увеличивает x на единицу и возвращает 4, x = 4;
  3. x = 3 + (x) -> x подсчитывается и возвращает 4, x = 4;
  4. x = 3 + 4 -> выражение 3 + 4 подсчитывается и возвращает 7, x = 4;
  5. (x = 7) -> x присваивается значение 7 (переписывая предыдущее значение 4).

Я надеюсь, теперь все ясно. Кстати, в языке С++ поведение такого выражения не определено.

Так почему же мы определили поведение такого выражения? Почему мы не говорим об ошибке или почему не происходит предупреждения во время компиляции?

  • Мы были неправы, мы должны получить ошибку или предупреждение, но теперь уже слишком поздно, потому что если мы изменим это поведение, то можем сломать код; ИЛИ
  • Довольно сложно, сформировать набор руководящих правил для компилятора, чтобы он был способен сказать об ошибке в таких странных случаях; ИЛИ
  • Мы предпочитаем тратить наше время, работая над вещами, которые действительно заботят людей вместо сглаживания таких острых углов.

Имеет ли значение, какой из предыдущих вариантов является правильным? Не совсем, потому что ВЫ НЕ ДОЛЖНЫ ПИСАТЬ ТАКОЙ КОД!

Автор: timyrik20

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js