简体   繁体   中英

lvalue required as increment operand - + unary operator

Can someone explain this:

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

int main (void) {

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

   return 0;
}

which should be

turning lvalue into rvalue example

according to this: What is the purpose of the unary plus (+) operator in C? , and gives error: lvalue required as increment operand . How does + unary operator work?

also another usage I found in this site:

 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

can someone explain that as well?

How does + unary operator work?

I believe the unary - is simpler to understand, because it actually "does" something "visible". I mean, having int k = 5 then -k is simple - it's turning the positive value 5 into a negative -5 . The unary - "calculates" the negative of it's operand.

The built-in unary + just returns the value of its operand. The end. It does nothing. However, applying the unary operator performs promotions on its argument that are specified in the standard. From cppreference operators :

The built-in unary plus operator returns the value of its operand. The only situation where it is not a no-op is when the operand has integral type or unscoped enumeration type, which is changed by integral promotion, eg, it converts char to int or if the operand is subject to lvalue-to-rvalue, array-to-pointer, or function-to-pointer conversion.

So short value is promoted to int . Lvalues are changed to rvalues. Array types decay to a pointer. And a function types decay to a function pointers. Cppreference value transformations .

Lvalue ("left value") is something you can assign to. In your code i is a variable, you can i = 1 assign value 1 to i . And 2 + 2 is an rvalue ("right value") with value 4 - you can't "assign" anything to 2 + 2 , it already has a value.
+i is the result of unary + applied to i - i undergoes integer promotions and lvalue-to-rvalue conversion and the result of the unary + operation has the same value and type as i after those transformations.

Excerpt from C11 para 6.5.3.3 - item 2:

The result of the unary + operator is the value of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.

So basically, the effect is almost always a no-op with the exceptions of int type promotions to its operands. eg,

char a = 6;

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

Where because of the type promotion from char to int , the size of the operand a grew from 1 to 4 . The value of the operand, is returned unchanged.

From comments: "turning lvalue into rvalue", that is what I do not understand ...

The effect of placing parenthesis around (+1)

int j = (+i)++;  

In this expression (+i)++ , the order of precedence is forced by the parenthesis () to perform the transformation of i (from the expression +i ) from being an lvalue to an rvalue , lexically followed by ++ operator in an attempt to increment the value of i . ( lexically because this expression will never live beyond compile-time into run-time.) At this point, i is no longer an lvalue, consequently it is no longer assignable, therefore cannot accept the increment operation that would normally happen if the operand was still an lvalue.

It is interesting to note by way of illustration that the following expressions are perfectly legal:

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`.  

The unary operator + turns an lvalue into an rvalue .
The terms can essentially be thought of as assignable and not assignable respectively.

As also shown by these expressions:

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

is legal. But:

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

is not.

An lvalue is an expression that potentially designates an object (bytes in memory). The most common form of lvalue is simply a name: Given int x , float y , or char z[10] , then x , y , and z are lvalues. Another form of lvalue is the result of unary * : Given double *p; , then *p is an lvalue. 1

When we use lvalues to compute expressions, they are turned into the values of their objects: x+3 produces three more than whatever value is in x . In this expression x is used for its value . In contrast, in x = 7; , x is used directly as its lvalue; 7 is written to the bytes in memory, regardless of what value they previously contained.

Since the C standard must specify how compilers behave in technical details, it specifies that, when an lvalue is used in an expression in a place where we want its value, that lvalue is converted to a value. To emphasize that this result is just a number or similar thing and is no longer a reference to memory, it may be called an rvalue .

Unary + is an operator. When applied to an arithmetic value, it produces the same value. However, it only produces a value, not an lvalue. So applying + to an lvalue produces an rvalue.

Footnote

1 This is why an lvalue potentially designates an object: *p is an lvalue and is treated as such during compilation, but, when the program is executing, p might be set to a null pointer, so *p would not actually be an object. That would be an error in the program, but it is a run-time error.

The ++ operator expects its operand to be an lvalue - basically, an expression that can designate an object (in the C sense, a chunk of memory that can be used to store a value).

The result of the unary + operator, however, is not an lvalue. In this case, the result of +i is just the value 0 , so the expression is equivalent to writing 0++ . You can't apply the ++ operator to 0 the same way you can't write 0 = 1 - you cannot assign a value to a value, you can only assign a value to an object through an lvalue.

Note that following would work:

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

You're applying the + operator to the result of i++ , which would be 0 (the postfix ++ evaluates to the current value of i , and as a side effect increments i ). The result of i++ is not an lvalue either, but + does not require its operand to be an lvalue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM