приращение постфикса (префикса), L-значение и R-значение (в C и C++)

Я только что узнал следующие факты:

  • Результатом приращения префикса (++имя_переменной) является R-значение в C (по крайней мере, я уверен, что это не L-значение в C), но это L-значение в C++.

  • Результатом приращения постфикса (var_name++) является R-значение в C (по крайней мере, я уверен, что это не L-значение в C). Это также верно в C++ (он говорит, что результатом является prvalue).

Я проверил их в VS2010 (.cpp и .c) и Ubuntu (gcc и g++).

В стр. 109 (5.3.2) стандарта C++ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf, написано

Операнд префикса ++ изменяется путем добавления 1 или устанавливается равным true, если это логическое значение (это использование не рекомендуется). Операнд должен быть модифицируемым lvalue. Тип операнда должен быть арифметическим типом или указателем на полностью определенный объектный тип. Результатом является обновленный операнд; это lvalue и...

и в п.101, (5.2.6)

Значением постфиксного выражения ++ является значение его операнда. ... Результатом является prvalue. Тип результата — это cv-неквалифицированная версия типа операнда. См. также 5.7 и 5.17.

(Хотя я не знаю разницы между R-value и prvalue).

Что касается стандарта C, http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf, префикс ++ описан в 6.5.3.1, а постфикс в 6.5.2.4, но из описания я не могу понять , однозначный ответ.

Я хотел бы знать причины, по которым они являются значением R или значением L. Все, что я знаю, это то, что

We can assign a value to a (modifiable) L-value, for example, a variable name. R-value is a value of an expression.

Но я не знаю подробностей, почему постфикс ++ не является L-значением в C и C++, и почему префикс ++ не является в C. (я видел что-то вроде «postfix ++. ..хранить...тогда по временному адресу...", но я так и не понял).

И еще вопрос, почему префикс ++ в C и C++ разный? Создание префикса ++ L-значением (в С++) имеет много преимуществ? Если да, то почему C не меняет этого? (Другие причины, кроме обратной совместимости, или, по крайней мере, почему ее изменение вызовет много проблем).


person user565739    schedule 25.01.2014    source источник
comment
Вы сказали, что проверили свои предположения в VS2010 и gcc. Какой код вы использовали для проверки своих предположений об этих проблемах?   -  person Brandin    schedule 25.01.2014
comment
(Я видел что-то вроде постфикса ++... хранить... во временном адресе, тогда..., но я все еще не понимаю) - Может быть, если вы процитируете все предложение из стандарта, которого вы не получить, кто-то может разъяснить это для вас.   -  person Brandin    schedule 25.01.2014
comment
@Brandin, этого нет в стандарте. Я видел это в книге, в которой говорится, что выражение a++ в третьем утверждении является значением r, потому что оно временно сохраняет значение a как результат выражения, а затем увеличивает a .   -  person user565739    schedule 25.01.2014
comment
Кроме того, просто используя такие операторы, как (a++) = 3, (++a) = 3.   -  person user565739    schedule 25.01.2014
comment
Дают ли эти примеры разные результаты на разных компиляторах C и C++? Я думал, что ваш вопрос был о разнице между C и C++.   -  person Brandin    schedule 25.01.2014
comment
Нет, результаты точно такие же, как описано в стандартах, в каждом компиляторе, который я пробовал. Мой вопрос о разнице между C и C++, как вы сказали, а не о компиляторе.   -  person user565739    schedule 25.01.2014
comment
Этот стандарт (N3242) довольно старый.   -  person Shoe    schedule 25.01.2014
comment
Это 2011 год. Это старо?   -  person user565739    schedule 25.01.2014


Ответы (2)


C и C++ - разные языки. C++ имеет перегрузку операторов, а C — нет. Операторы ++, префиксные или постфиксные, могут быть перегружены в C++. C++ также имеет ссылки, а C — нет.

В C ++i и i++ дают значение, которое не является lvalue. Это желательно, так как в противном случае вы можете столкнуться с неопределенным поведением, пытаясь изменить один и тот же скаляр в пределах одних и тех же границ точек следования.

Пища для размышлений: в C оператор запятой также создает значение, которое не является lvalue, поэтому, чтобы «отбросить» lvalueness, вы можете сделать:

(0, lvalue)
person Shao    schedule 15.08.2014

Правда, что

  • оператор предварительного увеличения/уменьшения (++var или --var) дает lvalue (т.е. изменяемый объект)

  • постинкрементный/декрементный оператор (var++ или var--) дает rvalue (т.е. временный объект).

Рассмотрим следующий код с оператором предварительного увеличения/уменьшения

{

int i = 0;

int* pi = &(++i);

}

Это нормально, потому что на самом деле его псевдокод

i = i+1; // pre increment i

int* pi = &i; // then evaluate its address and assign it to pi 

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

{

int i = 0;

int* pi = &(i++); // Not OK !! because it is a temporary variable

}

Его псевдокод будет

int i = 0;

int tmp = i; // compiler creates a temporary variable to save value of i

int* pi = &tmp; // then would take the address of a temporary variable 

i = i + 1; 
person Barhom    schedule 04.07.2017