интервал [] прибытие = {0}; международное значение = прибытие [прибытие [0] ++]; Значение = 1?

Сегодня я приехал крест статья Eric Lippert, где он пытался очистить миф между приоритетом операторов и порядком оценки. В конце было два фрагмента кода, которые получили меня перепутанный, вот первый отрывок:

      int[] arr = {0};
      int value = arr[arr[0]++];

Теперь, когда я думаю о значении значения переменной, я просто вычисляю его, чтобы быть тем. Вот то, как я думал, что это работает.

  1. Сначала объявите прибытие как массив интервала с одним объектом в нем; значение этого объекта 0.
  2. Второй получают значение прибытия [0] - 0 в этом случае.
  3. Треть получает значение прибытия [значение шага 2] (который является все еще 0) - получает прибытие [0] снова - все еще 0.
  4. Четвертый присваивают значение шага 3 (0) к значению переменной. - оценивают = 0 теперь
  5. Добавьте к значению шага 2 1 - Теперь прибытие [0] = 1.

По-видимому, это неправильно. Я пытался искать c# спецификации некоторый явный оператор о том, когда инкремент на самом деле происходит, но не нашел никого.
Второй отрывок из комментария сообщения в блоге Eric по теме:

 int[] data = { 11, 22, 33 }; 
 int i = 1;
 data[i++] = data[i] + 5;

Теперь вот то, как я думаю, что эта программа выполнится - после объявления массива и присвоения 1 мне. [терпите меня]

  1. Получите данные [я] - 1
  2. Добавьте к значению шага 1 значение 5 - 6
  3. Присвойте данным [я] (который равняется все еще 1), значение шага 2 - данные [я] = 6
  4. Инкремент i - я = 2

Согласно моему пониманию, этот массив теперь должен содержать значения {11, 27, 33}. Однако, когда я циклично выполнился для печати значений массива, я добрался: {11, 38, 33}. Это означает, что инкремент сообщения произошел прежде, чем разыменовать массив!
Каким образом? Разве это сообщение не является инкрементом, который, как предполагают, был сообщением? т.е. произойдите после всего остального.
Что я скучаю по парням?

12
задан Robert Harvey 5 July 2011 в 14:59
поделиться

6 ответов

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

Другими словами, для любого выражения E, E ++ (если допустимо) представляет что-то вроде (псевдокода):

T tmp = E;
E += 1;
return tmp;

Это все часть оценки E ++, прежде чем что-либо еще будет оценено.

См. Раздел 7.5.9 спецификации C # 3.0 для более подробной информации.


Кроме того, для операций присваивания, когда LHS классифицируется как переменная (как в этом случае), LHS оценивается до RHS оценивается.

Итак, в вашем примере:

int[] data = { 11, 22, 33 }; 
int i = 1;
data[i++] = data[i] + 5;

эквивалентно:

int[] data = { 11, 22, 33 }; 
int i = 1;
// Work out what the LHS is going to mean...
int index = i;
i++;
// We're going to assign to data[index], i.e. data[1]. Now i=2.

// Now evaluate the RHS
int rhs = data[i] + 5; // rhs = data[2] + 5 == 38

// Now assign:
data[index] = rhs;

Соответствующий бит спецификации для этого раздел 7.16.1 (спецификация C # 3.0).

18
ответ дан 2 December 2019 в 07:22
поделиться
data[i++] // => data[1], then i is incremented to 2

data[1] = data[2] + 5 // => 33 + 5
2
ответ дан 2 December 2019 в 07:22
поделиться

Для первого фрагмента последовательность такова:

  1. Объявить arr, как вы описали:
  2. Получить значение arr [0], равное 0
  3. Увеличить значение arr [0] - 1.
  4. Получить значение arr [(результат # 2)], которое есть arr [0], которое (для # 3) равно 1.
  5. Сохраните результат в значение .
  6. value = 1

Для второго фрагмента оценка по-прежнему выполняется слева направо.

  1. Где мы сохраняем результат? В данных [i ++], которые являются данными [1], но теперь i = 2
  2. Что мы добавляем? data [i] + 5, который теперь является data [2] + 5, который равен 38.

Отсутствует то, что «post» не означает «после ВСЕГО остального». Это просто означает «сразу после того, как я получу текущее значение этой переменной». Приращение поста, происходящее «в середине» строки кода, совершенно нормально.

5
ответ дан 2 December 2019 в 07:22
поделиться

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

Если это не так, вы можете написать

data[i++] = data[i++] + data[i++] + data[i++] + 5

Если это будет так, как вы говорите, тогда вы можете удалить оператор увеличения, потому что он не В инструкции, которую я сообщил, фактически ничего не делаю.

0
ответ дан 2 December 2019 в 07:22
поделиться

Вы должны подумать о назначениях в три этапа:

  1. Вычислить левую часть (= получить адрес, где должно быть сохранено значение)
  2. Вычислить правую часть
  3. Назначить значение из шага 2 в ячейку памяти из шага 1.

Если у вас есть что-то вроде

A().B = C()

Тогда сначала будет выполняться A (), затем будет выполняться C (), а затем будет запущено средство задания свойств B.

По сути, вы должны думать о своем заявлении как

StoreInArray(data, i++, data[i] + 5);
0
ответ дан 2 December 2019 в 07:22
поделиться

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

У меня сейчас нет доступа к Visual Studio, чтобы подтвердить это, но попробуйте отключить код оптимизации и посмотрите, останутся ли результаты такими же.

-4
ответ дан 2 December 2019 в 07:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: