Почему я не могу делать ++ я ++ в C-подобных языках?

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

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

Ответ 1

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

Ответ 2

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

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

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

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

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

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

Предположим, что я равно 10. Значение я ++ должно быть "получить значение я - 10 - увеличить его - 11 - сохранить его - я теперь 11 - и дать исходное значение в качестве результата - 10". Поэтому, когда вы говорите print (i ++), он должен печатать 10, а 11 должен храниться в i.

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

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

Ответ 3

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

Ответ 4

Я тестировал (++ 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

Ответ 5

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

Ответ 6

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

Ответ 7

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

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

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

Ответ 8

Это написано более кратко, чем "Его и lvalue".

На уровне компилятора:

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