Увеличение до и после в C#
Я немного озадачен тем, как компилятор C# обрабатывает до и после увеличения и уменьшения.
Когда я кодирую следующее:
int x = 4;
x = x++ + ++x;
x
будет иметь значение 10 впоследствии. Я думаю, это потому, что наборы предварительного увеличения x
в 5
что делает это 5+5
который оценивает 10
, Тогда постинкремент обновится x
в 6
, но это значение не будет использоваться, потому что тогда 10
будет назначен на x
,
Но когда я кодирую:
int x = 4;
x = x-- - --x;
затем x
будет 2
после этого. Кто-нибудь может объяснить, почему это так?
6 ответов
x--
будет 4, но будет 3 на момент --x
, так что это будет 2, то у вас будет
x = 4 - 2
Кстати, ваш первый случай будет x = 4 + 6
Вот небольшой пример, который распечатает значения для каждой части, возможно, так вы поймете это лучше:
static void Main(string[] args)
{
int x = 4;
Console.WriteLine("x++: {0}", x++); //after this statement x = 5
Console.WriteLine("++x: {0}", ++x);
int y = 4;
Console.WriteLine("y--: {0}", y--); //after this statement y = 3
Console.WriteLine("--y: {0}", --y);
Console.ReadKey();
}
это распечатывает
x++: 4
++x: 6
y--: 4
--y: 2
Давайте посмотрим на IL, который генерируется из этого оператора
IL_0002: ldloc.0
Загружает значение x в стек. Стек => (4)
IL_0003: dup
Дублирует самый верхний элемент в стеке. Стек => (4, 4)
IL_0004: ldc.i4.1
Нажмите 1 на стек. Стек => (1, 4, 4)
IL_0005: sub
Вычтите два верхних значения и поместите результат в стек. Стек => (3, 4)
IL_0006: stloc.0
Сохраните самое верхнее значение стека обратно в x. Стек => (4)
IL_0007: ldloc.0
Загрузите значение x обратно в стек. Стек => (3, 4)
IL_0008: ldc.i4.1
Загрузите значение 1 в стек. Стек => (1, 3, 4)
IL_0009: sub
Вычтите два. Стек => (2, 4)
IL_000A: dup
Дублировать верхнее значение => (2, 2, 4)
IL_000B: stloc.0
Сохраните верхнее значение обратно в x. Стек => (2, 4)
IL_000C: sub
Вычтите два верхних значения. Стек => (2)
IL_000D: stloc.0
Сохраните это значение обратно в x. х == 2
Из вашего комментария:
Я думал, что пост- и преинкременты выполняются после / до оценки всей кодовой строки - но они выполняются после / до оценки каждого элемента в выражении.
Ваше недоразумение является чрезвычайно распространенным. Обратите внимание, что в некоторых языках, таких как C, оно не указывается, когда побочный эффект становится видимым, и поэтому допустимо, но не обязательно, чтобы ваше утверждение было истинным в C.
Это не так в C#; в C# побочные эффекты кода на левой стороне выражения всегда наблюдаются до выполнения кода на правой стороне (из одного потока; в многопоточных сценариях все ставки отключены).
Для более подробного объяснения того, что делают операторы инкремента в C#, смотрите:
В чем разница между i++ и ++i?
Там очень много дополнительных ссылок на статьи, которые я написал по этой часто неправильно понимаемой теме.
Самое интересное, что вы получите совершенно другой ответ с компилятором C++.NET.
int x = 4;
x = x++ + ++x; // x = 11
x = 4;
x = x-- - --x; // x = -1
Конечно, разница в результатах определяется различной семантикой - это кажется нормальным. Но, несмотря на понимание того факта, что два компилятора.net не ведут себя одинаково для таких базовых вещей, меня тоже смущает.
В этом примере
int x = 4;
x = x++ + ++x;
Вы можете сломать это как:
x = 4++; which is = 5
x = 4 + ++5; which is 4 + 6
x = 10
Так же,
int x = 4;
x = x-- - --x;
Вот,
x = 4--; which is = 3
x = 4 - --3; which is 4 - 2
x = 2
Проще говоря, вы можете сказать, заменить текущее значение x, но для каждого ++ или - добавить / вычесть значение из x.
Я думаю, что объяснение для случая ++ + ++ неверно:
команда........... значение х
.................. не определен
int x = 4.......... 4
х ++...............5 (первое слагаемое 4)
++ x............... 6 (второе слагаемое 6)
x = summand1 + summand2..4 + 6 = 10
Аналогичное объяснение для случая - - -
команда........... значение х
.................. не определен
int x = 4.......... 4
х --...............3 (подвектор 4)
--x............... 2 (вычитаемое 2)
х = вычитающее-вычитаемое..4-2=10