Почему я не могу сделать ++ i ++ на C-подобных языках? - PullRequest
27 голосов
/ 02 октября 2009

Наполовину в шутку, наполовину серьезно : Почему я не могу сделать ++i++ на C-подобных языках, особенно на C #?

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

Ответы [ 7 ]

84 голосов
/ 02 октября 2009

Хотя краткий ответ "это не lvalue" правильный , возможно, это просто вопрос. Почему не является ли значением ? Или, как мы говорим в C #, переменная .

Причина в том, что вы не можете получить свой пирог и съесть его тоже . Работай логически:

Во-первых, значение оператора ++ в C #, будь то постфикс или префикс, "принимает значение этой переменной, увеличивает значение, назначает новое значение переменной и создает значение как результат ". Значение, полученное в результате, является либо исходным значением, либо увеличенным значением, в зависимости от того, был ли это постфикс или префикс. Но так или иначе, вы производите ценность.

Во-вторых, значение переменной всегда является текущим содержимым этой переменной . (По модулю определенных причудливых сценариев с многопоточностью, которые уведут нас далеко).

Надеюсь, вы согласны с тем, что это совершенно разумные правила.

Теперь должно быть понятно, почему результат i ++ не может быть переменной, но если это не так, позвольте мне прояснить:

Предположим, что i равно 10. Значение i ++ должно быть следующим: «получить значение i - 10 - увеличить его - 11 - сохранить - i теперь 11 - и дать исходное значение в качестве результата - 10». Таким образом, когда вы говорите print (i ++), он должен вывести 10, а 11 должен быть сохранен в i.

Теперь предположим, что смысл i ++ - возвращать переменную , а не значение . Вы говорите print (i ++) и что происходит? Вы получаете значение i - 10 - увеличиваете его - 11 - сохраняете - i теперь 11 - и возвращаете переменную в результате. Каково текущее значение переменной? 11! Что именно то, что вы не хотите печатать.

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

57 голосов
/ 02 октября 2009

Краткий ответ: i++ не является "lvalue", поэтому не может быть предметом назначения.

18 голосов
/ 02 октября 2009

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

8 голосов
/ 02 октября 2009

Я тестировал (++ i, i ++) как обходной путь:

#include <stdio.h> 

int main(){
  int i=0;

  printf(" i:         %i\n", i         );
  printf(" (++i,i++): %i\n", (++i,i++) );
  printf(" i:         %i\n", i         );
}

Результат:


i:         0
(++i,i++): 1
i:         2
6 голосов
/ 02 октября 2009

Потому что результат i++ не является lvalue.

3 голосов
/ 02 октября 2009

Из раздела 7.5.9 спецификации C # 3.0 :

Операнд приращения постфикса или операция декремента должна быть выражение классифицируется как переменная, а доступ к свойству или доступ к индексатору. Результатом операции является значение того же типа, что и операнд. Если операнд приращения постфикса или операция декремента является свойством или индексатор доступа, свойство или индексатор должен иметь как get, так и набор сбруя. Если это не так, Произошла ошибка во время компиляции.

Кроме того, выражение после увеличения (i++) будет оцениваться первым, поскольку оно имеет более высокий приоритет, чем оператор предварительного увеличения (++i).

3 голосов
/ 02 октября 2009

Я считаю, что оператору приращения (или уменьшения) нужно присвоить lvalue. Однако ++ я не lvalue, это выражение. Кто-то, кто лучше разбирается в компиляторах, может выяснить, есть ли техническая причина для этого ограничения.

...