Увеличение до и после в C # - PullRequest
61 голосов
/ 20 декабря 2011

Я немного озадачен тем, как компилятор 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 ]

50 голосов
/ 20 декабря 2011

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
18 голосов
/ 20 декабря 2011

Давайте посмотрим на 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. x == 2

9 голосов
/ 20 декабря 2011

Из вашего комментария:

Я думал, что пост- и преинкременты выполняются после / до оценки всей кодовой строки - но они выполняются после / до оценки каждого элемента ввыражение.

Ваше недопонимание является чрезвычайно распространенным.Обратите внимание, что в некоторых языках, таких как C, оно не указывается, когда побочный эффект становится видимым, и поэтому допустимо, но не обязательно, чтобы ваше утверждение было истинным в C.

Это не так вC #;в C # побочные эффекты кода на левой стороне выражения всегда наблюдаются до того, как код на правой стороне исполняется (из одного потока; в многопоточных сценариях все ставки отключены).

Для более подробного объяснения того, что делают операторы инкремента в C #, смотрите:

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

Естьтам очень много дополнительных ссылок на статьи, которые я написал по этой часто неправильно понимаемой теме.

6 голосов
/ 20 декабря 2011

Самое интересное, что вы получите совершенно другой ответ с компилятором C ++. Net.

int x = 4;
x = x++ + ++x; // x = 11
x = 4;
x = x-- - --x; // x = -1

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

2 голосов
/ 20 декабря 2011

В этом примере

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.

0 голосов
/ 20 декабря 2011

Я думаю, что объяснение для случая ++ + ++ неверное:

команда ........... значение x

.................. undefined

int x = 4 .......... 4

x ++ ............... 5 (первое слагаемое 4)

++ x ............... 6 (второе слагаемое 6)

x = summand1 + summand2 ..4 + 6 = 10

Аналогичным объяснением для случая - - - является

команда ........... значениеиз х

.................. undefined

int x = 4 .......... 4

x --............... 3 (подвектор 4)

- x ...............2 (вычитаемое 2)

x = вычитающее-вычитаемое .. 4-2 = 10

...