Лучший отвечающий
x += x++ Как выполняется выражение в С#

Вопрос
-
Добрый день!
Подскажите, как выполняется выражение в C# x += x++ ?
int x = 3; x += x++;
Согласно Приоритет и порядок вычисления в С#
данное выражение должно быть равносильно x=4+3 т.е. в итоге x=7, но на деле получается 6 (почему-то постфиксный инкремент не обновляет значение переменной x значением x+1)
Объясните, почему так получается?
- Изменено Развитёр 24 ноября 2016 г. 6:09
24 ноября 2016 г. 6:07
Ответы
-
Выражения в C# выполняются с лево на право. Если расписать Ваше выражение, то получится следующие:
int x = 3; int t1 = x; // 3 int t2 = x++; // 3 x = t1 + t2 // 6
- Предложено в качестве ответа VadimTagil 23 декабря 2016 г. 19:37
- Помечено в качестве ответа Maksim MarinovMicrosoft contingent staff, Moderator 27 декабря 2016 г. 8:50
24 ноября 2016 г. 8:37 -
Приоритет и порядок выполнения это разные вещи. В вашем случае у оператора
+=
два операндаx
иx++
. Так как C# вычисляет выражения с лева на право, то сначала будет вычислен левый операндx
(t1
в моём коде) в результате Вы получите значение переменнойx
в момент вычисления (не ссылку на переменнуюx
, а именно значение), а только потом будет вычислен правый операндx++
(t2
в моём коде). Затем будет вычислен сам оператор +=.- Помечено в качестве ответа Maksim MarinovMicrosoft contingent staff, Moderator 27 декабря 2016 г. 8:50
24 ноября 2016 г. 13:42
Все ответы
-
Я бы сказал что результат не определен и может быть разным в зависимости от реализации JIT, процессора, уровня оптимизации, наличия отладчика и т.п. Дело в том что компилятор использует копии переменных считая их равными самим переменным, а в подобных случаях это не так.
Например, 6 выйдет если сначала сложили 3 + 3 в регистре (получив 6), потом увеличили х до 4 (помните что 6 еще не записано в память), а потом занесли предыдущий результат. Можете попробовать разные варианты очередности и посмотрите какие еще значения можно получить. Думаю 4 и 7 вполне возможны.
Это в общем то всем известная фишка, поэтому важно так никогда не делать. Если вам просто интересно то переключите на ассемблер и посмотрите что именно происходит.
This posting is provided "AS IS" with no warranties, and confers no rights.
- Предложено в качестве ответа VadimTagil 23 декабря 2016 г. 19:37
24 ноября 2016 г. 7:25Модератор -
int x = 3; x += x++; Console.WriteLine(x.ToString()); Console.ReadKey();
В IL превращается в:
.entrypoint // Code size 29 (0x1d) .maxstack 4 .locals init ([0] int32 x) IL_0000: ldc.i4.3 //Push num of type int32 onto the stack as int32. IL_0001: stloc.0 //Pop a value from stack into local variable 0. IL_0002: ldloc.0 //Load local variable 0 onto stack. В стеке:3 IL_0003: ldloc.0 //Load local variable 0 onto stack. В стеке:3|3 IL_0004: dup //Duplicate the value on the top of the stack. В стеке:3|3|3 IL_0005: ldc.i4.1 //Push num of type int32 onto the stack as int32. В стеке:3|3|3|1 IL_0006: add //Add two values, returning a new value. В стеке:3|3|4 IL_0007: stloc.0 //Pop a value from stack into local variable 0. В стеке:3|3 IL_0008: add //Add two values, returning a new value. В стеке:6 IL_0009: stloc.0 //Pop a value from stack into local variable 0. IL_000a: ldloca.s x //Load address of local variable with index indx. IL_000c: call instance string [mscorlib]System.Int32::ToString() IL_0011: call void [mscorlib]System.Console::WriteLine(string) IL_0016: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey() IL_001b: pop IL_001c: ret
Т.е. полученная четверка просто отбрасывается? Мда. Я догадывался, что сложные выражения использовать плохо, но не знал что настолько...
- Предложено в качестве ответа VadimTagil 23 декабря 2016 г. 19:37
24 ноября 2016 г. 7:39 -
Спецификация C# строго определяет последовательность вычисления выражений, так что результат всегда будет один и тот же.24 ноября 2016 г. 8:28
-
Выражения в C# выполняются с лево на право. Если расписать Ваше выражение, то получится следующие:
int x = 3; int t1 = x; // 3 int t2 = x++; // 3 x = t1 + t2 // 6
- Предложено в качестве ответа VadimTagil 23 декабря 2016 г. 19:37
- Помечено в качестве ответа Maksim MarinovMicrosoft contingent staff, Moderator 27 декабря 2016 г. 8:50
24 ноября 2016 г. 8:37 -
Выражения в C# выполняются с лево на право. Если расписать Ваше выражение, то получится следующие:
int x = 3; int t1 = x; // 3 int t2 = x++; // 3 x = t1 + t2 // 6
Но есть же ещё приоритеты, например умножение выполнится в первую очередь перед сложением независимо справа оно стоит или слева.
В рассматриваемом случае
x += x++
сначала выполняется ++, потом уже +=
- Изменено Развитёр 24 ноября 2016 г. 10:55
24 ноября 2016 г. 10:53 -
https://msdn.microsoft.com/en-us/library/36x43w8w.aspx
"The second form is a postfix increment operation. The result of the operation is the value of the operand before it has been incremented."
выполняться то он выполняется, но толку 0. постфиксный инкремент возвращает значение ДО инкремента, оно и идет в следующую операцию.
в листинге IL видно, как четверка честно вычисляется до операции суммирования и помещается в переменную 0, но потом перезаписывается 6-кой
24 ноября 2016 г. 11:23 -
Всё равно не пойму, раз инкремент выполняется первым, то в переменную x после его выполнения должно быть записано значение 4, т.е. x=4+3=7. Почему в итоге записывается всё равно 3? Это какой-то баг?24 ноября 2016 г. 11:53
-
Приоритет и порядок выполнения это разные вещи. В вашем случае у оператора
+=
два операндаx
иx++
. Так как C# вычисляет выражения с лева на право, то сначала будет вычислен левый операндx
(t1
в моём коде) в результате Вы получите значение переменнойx
в момент вычисления (не ссылку на переменнуюx
, а именно значение), а только потом будет вычислен правый операндx++
(t2
в моём коде). Затем будет вычислен сам оператор +=.- Помечено в качестве ответа Maksim MarinovMicrosoft contingent staff, Moderator 27 декабря 2016 г. 8:50
24 ноября 2016 г. 13:42