После исследования я прочитал, что оператор инкремента требует, чтобы операнд имел изменяемый объект данных: https://en.wikipedia.org/wiki/Increment_and_decrement_operators .
Исходя из этого, я предполагаю, что это дает ошибку компиляции, потому что (a+b)
это временное целое число, поэтому его нельзя изменить.
Это понимание правильное? Это был мой первый раз, когда я пытался исследовать проблему, поэтому, если я должен был что-то искать, пожалуйста, сообщите.
c = a + b + 1
ваше намерение становится более ясным, а также короче для ввода. Операторы увеличения / уменьшения делают две вещи: 1. они и их аргумент формируют выражение (которое может использоваться, например, в цикле for), 2. они изменяют аргумент. В вашем примере вы используете свойство 1., но не свойство 2., поскольку вы выбрасываете измененный аргумент. Если вам не нужно свойство 2. и нужно просто выражение, то вы можете просто написать выражение, например x + 1 вместо x ++.Ответы:
Это просто правило, вот и все, и, возможно, оно существует для (1) упрощения написания компиляторов C и (2) никто не убедил комитет по стандартам C ослабить его.
Неформально говоря, вы можете писать, только
++foo
если ониfoo
могут появиться в левой части выражения присваивания, напримерfoo = bar
. Поскольку вы не можете писатьa + b = bar
, вы не можете и писать++(a + b)
.Нет реальной причины, по которой
a + b
нельзя было бы создать временное, на котором++
можно было бы работать, и результатом этого является значение выражения++(a + b)
.источник
++
иногда имелся побочный эффект изменения чего-либо, а иногда просто нет.Стандарт C11 гласит в разделе 6.5.3.1.
А "изменяемое lvalue" описано в разделе 6.3.2.1, подраздел 1.
So
(a+b)
не является изменяемым lvalue и поэтому не подходит для оператора увеличения префикса.источник
Ты прав.
++
пытается присвоить новое значение исходной переменной. Итак++a
, возьмем значениеa
, добавим1
к нему, а затем вернем егоa
. Поскольку, как вы сказали, (a + b) является временным значением, а не переменной с назначенным адресом памяти, назначение не может быть выполнено.источник
Я думаю, вы в основном ответили на свой вопрос. Я мог бы внести небольшое изменение в вашу формулировку и заменить «временную переменную» на «rvalue», как упомянул К. Гиббонс.
Термины переменная, аргумент, временная переменная и т. Д. Станут более понятными по мере того, как вы узнаете о модели памяти C (это выглядит как хороший обзор: https://www.geeksforgeeks.org/memory-layout-of-c-program/ ).
Термин «rvalue» может показаться непонятным, когда вы только начинаете, поэтому я надеюсь, что следующее поможет вам развить интуицию по этому поводу.
Lvalue / rvalue говорят о разных сторонах знака равенства (оператор присваивания): lvalue = левая сторона (строчная L, а не «единица») rvalue = правая сторона
Немного узнав, как C использует память (и регистры), будет полезно понять, почему это различие важно. В общих чертах компилятор создает список инструкций машинного языка, которые вычисляют результат выражения (rvalue), а затем помещает этот результат куда-нибудь (lvalue). Представьте компилятор, имеющий дело со следующим фрагментом кода:
В псевдокоде ассемблера это может выглядеть примерно так:
Оператору ++ (и его аналогу) требуется «где-то» для изменения, по существу все, что может работать как lvalue.
Понимание модели памяти C будет полезно, потому что вы получите лучшее представление о том, как аргументы передаются функциям и (в конечном итоге) как работать с динамическим распределением памяти, например с функцией malloc (). По тем же причинам вы можете в какой-то момент изучить простое программирование на ассемблере, чтобы лучше понять, что делает компилятор. Также, если вы используете gcc , опция -S «Остановить после стадии собственно компиляции; не собирать». может быть интересным (хотя я бы рекомендовал попробовать его на небольшом фрагменте кода).
Просто в сторону: инструкция ++ существует с 1969 года (хотя она началась в предшественнике C, B):
Следуя этой ссылке в Википедии, вы перейдете к интересной статье Денниса Ричи («R» в «K&R C») по истории языка C, ссылка на которую для удобства приведена здесь: http://www.bell-labs.com/ usr / dmr / www / chist.html, где вы можете искать "++".
источник
Причина в том, что стандарт требует, чтобы операнд был lvalue. Выражение
(a+b)
не является lvalue, поэтому применение оператора увеличения не допускается.Теперь, можно сказать : «Хорошо, что это на самом деле причина, но на самом деле нет * реального * причины кроме этого» , но несчастию конкретной формулировки того , как оператор работает фактически делает требовать, чтобы быть.
Очевидно, вы не можете писать,
E += 1
еслиE
не lvalue. Это позор, потому что с таким же успехом можно было сказать: «увеличивает E на единицу» и готово. В этом случае применение оператора к значению, отличному от lvalue, было бы (в принципе) совершенно возможным за счет немного усложнения компилятора.Теперь определение можно было бы тривиально перефразировать (я думаю, что это даже не изначально C, а семейная реликвия B), но это в корне изменило бы язык на то, что больше не совместимо с его предыдущими версиями. Поскольку возможная выгода довольно мала, но возможные последствия огромны, этого никогда не было и, вероятно, никогда не произойдет.
Если вы рассмотрите C ++ в дополнение к C (вопрос помечен как C, но обсуждались перегрузки операторов), история становится еще более сложной. В C трудно представить, что это могло быть так, но в C ++ результатом
(a+b)
вполне может быть что-то, что вы вообще не можете увеличить, или увеличение может иметь очень значительные побочные эффекты (а не просто добавление 1). Компилятор должен уметь справляться с этим и диагностировать проблемные случаи по мере их возникновения. При lvalue это все еще тривиально проверить. Но не в отношении любого случайного выражения в скобках, которое вы бросаете бедняге.Это не настоящая причина, по которой он не мог быть сделано, но это, несомненно, служит объяснением того, почему люди, которые реализовали это, не совсем в восторге от добавления такой функции, которая обещает очень мало пользы для очень немногих людей.
источник
(a + b) оценивает значение r, которое не может быть увеличено.
источник
++ пытается передать значение исходной переменной и, поскольку (a + b) является временным значением, он не может выполнить операцию. И они, по сути, являются правилами соглашений о программировании на C, чтобы упростить программирование. Вот и все.
источник
Когда выполняется выражение ++ (a + b), тогда, например:
источник