lvalue требуется как операнд приращения - + унарный оператор - PullRequest
1 голос
/ 07 мая 2020

Может кто-нибудь объяснить это:

#include <stdio.h>
#include <stdlib.h>

int main (void) {

   int i = 0,j;
   j=(+i)++;

   return 0;
}

который должен быть

превращение lvalue в пример rvalue

в соответствии с этим: Какова цель оператора унарного плюса (+) в C? и выдает ошибку: lvalue required as increment operand. Как работает унарный оператор +?

также другое использование, которое я нашел на этом сайте:

 little known: The unary plus operator can be used as an "decay
 operator": Given int a[10]; int b(void);, then +a is an int pointer
 and +b is a function pointer. Useful if you want to pass it to a
 template accepting a reference

может кто-нибудь объяснить это?

Ответы [ 4 ]

1 голос
/ 07 мая 2020

Как работает + унарный оператор?

Я считаю, что унарный - проще понять, потому что он на самом деле «делает» что-то «видимое». Я имею в виду, что иметь int k = 5, а затем -k просто - это превращает положительное значение 5 в отрицательное -5. Унарный - «вычисляет» отрицательное значение своего операнда.

Встроенный унарный + просто возвращает значение своего операнда. Конец. Ничего не делает. Однако применение унарного оператора приводит к продвижению к его аргументу, которые указаны в стандарте. From операторы cppreference :

Встроенный унарный оператор плюс возвращает значение своего операнда. Единственная ситуация, когда это не бездействие, - это когда операнд имеет целочисленный тип или тип перечисления с незаданной областью, который изменяется интегральным продвижением, например, он преобразует char в int или если операнд подчиняется lvalue-to-rvalue, преобразование массива в указатель или функции в указатель.

Таким образом, значение short повышается до int. Lvalue заменены на rvalue. Типы массивов распадаются на указатель. И типы функций распадаются на указатели на функции. Преобразования значений Cppreference .

Lvalue («левое значение») - это то, чему вы можете присвоить. В вашем коде i - это переменная, вы можете i = 1 присвоить значение 1 i. И 2 + 2 - это rvalue («правильное значение») со значением 4 - вы не можете «назначить» что-либо на 2 + 2, оно уже имеет значение.
+i является результатом унарного +, примененного к i - i, подвергается целочисленному продвижению и преобразованию lvalue-to-rvalue, а результат унарной операции + имеет то же значение и тип, что и i после этих преобразований .

0 голосов
/ 07 мая 2020

Оператор ++ ожидает, что его операнд будет lvalue - в основном, выражением, которое может обозначать объект (в смысле C, кусок памяти, который может использоваться для хранения стоимость).

Однако результат унарного оператора + не является lvalue. В этом случае результатом +i будет просто значение 0, поэтому выражение эквивалентно записи 0++. Вы не можете применить оператор ++ к 0 так же, как вы не можете написать 0 = 1 - вы не можете присвоить значение значению, вы можете присвоить значение только объекту от до lvalue.

Обратите внимание, что следующее будет работать:

j = +(i++); // or just +i++, precedence is the same

Вы применяете оператор + к результату i++, который будет 0 (постфикс ++ оценивается как текущее значение i и как побочный эффект приращения i). Результат i++ также не является l-значением, но + не требует, чтобы его операнд был l-значением.

0 голосов
/ 07 мая 2020

lvalue - это выражение, которое потенциально обозначает объект (байты в памяти). Наиболее распространенная форма lvalue - это просто имя: если даны int x, float y или char z[10], тогда x, y и z являются lvalue. Другая форма lvalue является результатом унарного *: дано double *p;, тогда *p является lvalue. 1

Когда мы используем lvalue для вычисления выражений, они меняются в значения своих объектов: x+3 производит на три больше, чем любое значение в x. В этом выражении x используется в качестве значения . Напротив, в x = 7;, x используется непосредственно как его lvalue; 7 записывается в байты в памяти, независимо от того, какое значение они ранее содержали.

Поскольку стандарт C должен указывать, как компиляторы ведут себя в технических деталях, он указывает, что когда lvalue используется в выражении в том месте, где нам нужно его значение, это lvalue преобразуется в значение. Чтобы подчеркнуть, что этот результат представляет собой просто число или что-то подобное и больше не является ссылкой на память, его можно назвать rvalue .

Unary + - это оператор. При применении к арифметическому значению c он дает такое же значение. Однако он производит только значение, а не lvalue. Таким образом, применение + к lvalue дает rvalue.

Footnote

1 Вот почему lvalue потенциально обозначает объект: *p является lvalue и обрабатывается как таковое во время компиляции, но, когда программа выполняется, p может быть установлен в нулевой указатель, поэтому *p на самом деле не будет объектом. Это было бы ошибкой в ​​программе, но это ошибка времени выполнения.

0 голосов
/ 07 мая 2020

Выдержка из C11, параграф 6.5.3.3 - элемент 2:

Результатом унарного оператора + является значение его (продвинутого) операнда. Целочисленные рекламные акции выполняются для операнда, и результат имеет повышенный тип. * введите продвижение к своим операндам. например,

char a = 6;

size_t size_pre_promotion = sizeof(a);
size_t size_post_promotion = sizeof(+a);

Где из-за повышения type с char до int, размер операнд a вырос с 1 до 4. значение операнда возвращается без изменений.

Из комментариев: «превращение lvalue в rvalue», вот что Я не понимаю ...

Эффект помещения скобок вокруг (+1)

int j = (+i)++;  

В этом выражении (+i)++ порядок приоритета принудительно устанавливается скобками (), чтобы выполнить преобразование i (из выражения +i) из lvalue в rvalue, за которым следует лексический оператор ++ в попытке увеличить значение i. (lexically, потому что это выражение никогда не перестанет существовать вне времени компиляции во время выполнения.) На этом этапе i больше не является lvalue, следовательно, оно больше не может быть присвоено, поэтому не может принимать приращение операция, которая обычно происходила бы, если бы операнд все еще был lvalue.

Интересно отметить в качестве иллюстрации, что следующие выражения совершенно допустимы:

int j = (+i);//Not attempting to assign value (increment) the operand
             //so the _value_ returned from the operand is successfully assigned
             //to the lvalue `j`;


int j = +i++;//Assigns the i + 1 to j
        //in this case the `++` adds `1` to the operand, then the `+` unary operator returns the incremented value (essentially a no-op at this point),  which in turn is assigned to the _lvalue_ `j`.  

Унарный оператор + превращает lvalue в rvalue.
Термины можно рассматривать как присваиваемый и не назначаемый соответственно.

Как и показано этими выражениями:

int j;
&j; //address of an lvalue

является допустимым. Но:

&(+j);//cannot _take_ the address of an rvalue

нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...