Почему ++i считается lvalue, а i++ rvalue?
Я нашел ответ на данный вопрос на stackoverflow, но мой ужасный английский не позволяет мне грамотно в этом разобраться. Ведь приоритет префиксного и постфиксного ++ всё равно выше, чем & и по идее в любом случае будет сначала ++, а только потом & или я вообще не так понимаю?
- 2,089
6 Answers
Возможно, это очень неполный ответ по сравнению с развёрнутым первым по ссылке, но суть такая:
Постфиксный оператор меняет значение и возвращает только временную копию этого значения, которая, как следствие, не может быть изменена. То есть эта копия идёт отдельно от самого значения i, и может быть использована в выражении, но присваивание к i++ не имеет смысла, т.к. результат i++ сохраняется в какой-то другой ячейке памяти, не в той, где лежит i.
Результат ++i записывается в неё же, поэтому выражение ++i = ... имеет смысл (l-value).
- 2,828
Потому что после выполнения выражений:
i = 0;
(1) x = ++i;
(2) x = i++;
В x будут следующие значения:
(1) x = 1;
i = 1;
(2) x = 0;
i = 1;
Все эффекты связаны как раз с таким делением.
То есть ++i означает увеличить i на один и взять его для выражения, а i++ означает взять значение i для выражения и после увеличить i на 1.
-
IonRod вы путаете понятия префикс/постфикст с семантикой назначения, а это две разные вещи! – perfect Sep 18 '16 at 04:58
-
Век живи, век учись. Взял и попробовал обсуждаемые варианты.
#include <stdio.h>
#include <stdlib.h>
main ()
{
int i = 0, x;
x = (++i + ++i);
printf ("i = 0; x = (++i + ++i): x=%d i=%d\n",x,i);
i = 0;
x = (i++ + i++);
printf ("i = 0; x = (i++ + i++): x=%d i=%d\n",x,i);
x = x++;
printf ("x = x++: x=%d i=%d\n",x,i);
#ifdef __cplusplus
++i = x;
printf ("++i = x: x=%d i=%d\n",x,i);
#endif
}
c:/Users/avp/src/cc/tst $ gcc t.c
c:/Users/avp/src/cc/tst $ ./a
i = 0; x = (++i + ++i): x=4 i=2
i = 0; x = (i++ + i++): x=0 i=2
x = x++: x=0 i=2
c:/Users/avp/src/cc/tst $ g++ t.c
c:/Users/avp/src/cc/tst $ ./a
i = 0; x = (++i + ++i): x=4 i=2
i = 0; x = (i++ + i++): x=0 i=2
x = x++: x=0 i=2
++i = x: x=0 i=0
c:/Users/avp/src/cc/tst $ g++ --version
g++.exe (GCC) 3.4.5 (mingw-vista special r3)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
c:/Users/avp/src/cc/tst $ gcc --version
gcc.exe (GCC) 3.4.5 (mingw-vista special r3)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
c:/Users/avp/src/cc/tst $
c:/Users/avp/src/cc/tst $
- 46,098
- 6
- 48
- 116
Почему ++i считается lvalue, а i++ rvalue?
Потому что эти операторы так объявлены в соответствии со стандартом:
- Прединкремент возвращает ссылку. Ссылке можно присвоить значение, а потому она lvalue («left side value», величина слева от знака равенства).
- Постинкремент возвращает значение. Значению ничего присвоить нельзя; его самого присваивают, а потому оно rvalue («right side value», величина справа от знака равенства).
- 11,528
Оператор i++ никак не может возвращать lvalue по той простой причине, что нигде не существует подходящего lvalue для возвращения.
Постфиксный оператор ++ обязан возвращать старое значение своего операнда. Однако когда побочные эффекты постфиксного ++ возымели свое действие, его операнд уже поменял свое значение на новое, а старое значения операнда больше нигде в памяти не хранится. Т.е. возвращаемое lvalue просто некуда "привязывать" в памяти. Единственными способами возвращения старого значения является либо запоминание этого старого значения во временном объекте, либо его вычисление "на лету" из нового значения. В обоих случаях старое значение не будет lvalue.
Ситуация с префиксным оператором - обратная. Префиксный оператор должен возвращать новое значение своего операнда. Именно это новое значение операнд и будет содержать после реализации побочных эффектов префиксного ++. Поэтому операнд префиксного оператора как раз и является тем самым lvalue которое оператор сразу и вернет.
- 69,346
i++; /*называется постфиксной записью, в которой приоритет
операции низкий*/
++i; /*называется префиксной записью, в которой
приоритет операции высокий*/
/*----------------------------------------------------------------------------------*/
int i = 5;
int x = i++; /*здесь x == 5, а i == 6*/
int x = ++i; /*здесь x == 6, i == 6*/
- 1,823
++iдолжен возвращать значение, и++i =смысла не иметьP.S. - оператор меняет переменную, а возвращает значение – timka_s Nov 13 '11 at 09:40
++i = x;компилится и работает. Возвращает, но не во временную копию. – ivkremer Nov 13 '11 at 09:42i = 0; x = (++i + ++i );
При возврате ссылки,
– timka_s Nov 13 '11 at 10:14x = 4;При возврате значения,
x=3;x = x++; // переменная вообще не меняется
По-моему тут зависит от компилятора. Может поменяться, а может и нет.
– devoln Nov 13 '11 at 14:20