Половина шутки наполовину серьезная : Почему я не могу сделать ++i++
в C-подобных языках, в частности, на С#?
Я бы ожидал, что он увеличит значение, будет использовать его в моем выражении, а затем снова увеличится.
Половина шутки наполовину серьезная : Почему я не могу сделать ++i++
в C-подобных языках, в частности, на С#?
Я бы ожидал, что он увеличит значение, будет использовать его в моем выражении, а затем снова увеличится.
Короткий ответ: i++
не является "значением lvalue", поэтому не может быть предметом задания.
Хотя короткий ответ "это не lvalue" правильный, возможно, просто попрошайничать вопрос. Почему это не lvalue? Или, как мы говорим в С#, переменная.
Причина в том, что вы не можете иметь свой торт и съесть его тоже. Выполните логическую работу:
Во-первых, значение оператора ++ в С#, будь то постфикс или префикс, "принимает значение этой переменной, увеличивает значение, присваивает новое значение переменной и создает значение как результат" . Значение, полученное в результате, - это либо исходное значение, либо увеличенное значение, в зависимости от того, был ли он постфикс или префикс. Но в любом случае вы получаете ценность.
Во-вторых, значение переменной всегда является текущим содержимым этой переменной. (Подумайте о некоторых странных сценариях потоковой передачи, которые будут далеко от нас.)
Надеюсь, вы согласитесь, что это совершенно разумные правила.
Теперь должно быть понятно, почему результат я ++ не может быть переменной, но в случае, если это не так, позвольте мне пояснить:
Предположим, что я равно 10. Значение я ++ должно быть "получить значение я - 10 - увеличить его - 11 - сохранить его - я теперь 11 - и дать исходное значение в качестве результата - 10". Поэтому, когда вы говорите print (i ++), он должен печатать 10, а 11 должен храниться в i.
Теперь предположим, что значение я ++ - это вернуть переменную, а не значение. Вы говорите print (i ++) и что происходит? Вы получаете значение я - 10 - увеличиваете его - 11 - сохраняете его - теперь я 11 - и возвращаю переменную в результате. Какое текущее значение переменной? 11! Это именно то, что вы НЕ хотите печатать.
Короче говоря, если я ++ вернула переменную, то она будет делать точно противоположное предполагаемое значение оператора! Ваше предложение логически непоследовательно, поэтому ни один язык не делает этого.
Потому что вы заботитесь о том, чтобы следующий программист поддерживал (или пытался переписать) ваш код, долго после того, как вас уволили за нарушение популярных конвенций.
Я тестировал (++ 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
Потому что результат i++
не является значением l.
Я считаю, что оператору приращения (или декременту) требуется присвоить значение lvalue. Однако ++ я не является значением lvalue, это выражение. Кто-то, кто лучше разбирается в компиляторах, может уточнить, есть ли какая-либо техническая причина для этого ограничения.
Из раздела 7.5.9 спецификация С# 3.0:
Операнд поэтапного приращения или операция уменьшения должна быть выражение, классифицированное как переменная, доступ к ресурсу или доступ индексатора. Результатом операции является значение того же типа, что и операнд. Если операнд поэтапного приращения или операция декремента - это свойство или доступ индексатора, свойство или indexer должен иметь как get, так и набор сбруя. Если это не так, ошибка времени компиляции.
Кроме того, выражение post-increment (i++
) будет оцениваться первым, поскольку оно имеет более высокий приоритет, чем оператор pre-increment (++i
).
Это написано более кратко, чем "Его и lvalue".
На уровне компилятора:
Так как переменная не может иметь значение, которое изменяется более одного раза между двумя точками последовательности.
Несмотря на то, что пост-приращение происходит после текущего выражения, оно все еще находится в пределах тех же двух точек последовательности, что и выражение в целом. Между двумя точками последовательности компилятор может выполнять целый ряд отвратительных трюков оптимизации, которые потенциально могут выполнять множественное присвоение как (undefined или неуказанные или слова для этого эффекта).