In C, is there a way to identify the rvalues and lvalues ?
Some of them are easy to identity say, in an assignment, the left value is lvalue and the value in the right is rvalue.
But other scenarios, identification with such a rule is difficult.
For example : *p++
and i++
(where p is a pointer to integer and i is an integer) - how to identify whether it is an rvalue or lvalue ?
The context is ++*p++
works while ++i++
does not since i++
is an rvalue (as told by serious guys).
How to identify rvalue and lvalue in an expression?
The term lvalue has been with C (and was carried forward to C++ and expanded later on). There was no rvalue to begin with. The draft I have (N1570) does list two occurrences of the term rvalue -- oncee in footnote #64 and once in the index.
In a nutshell: In the C world you have two types of objects -- lvalues and everything else.
Note that footnotes are not part of the standard but they can provide some helpful insights. Here goes footnote 64:
This gives a good start. Now, bear in mind that an expression is built up from objects (and operators but we'll get there in a bit), and there are two fundamental things that you need to worry about when dealing with objects: Type and Value. Let's see what does the standard say about the type restrictions then (6.3.2.1/p1):
Also, note the next line which is important:
So, an lvalue can be used as a substitute for the type (we'll see this too). Next, let us take a look at the contexts where an object is an lvalue (6.3.2.1/2):
So, these are the operators that you need to keep an eye out for. In all other cases:
There are two special types: arrays and function designators. These decay i.e. are converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue / "pointer to function returning type". (Remember, we had paused on the fact that lvalues can work as types -- this is exactly what they do with
sizeof
and_Alignof
!)lvalue (from left-hand side (LHS) value) in something that refers to a memory (or register) storage and that you can assign values to.
*p++
is an lvalue since it is a dereferenced pointer (i.e. refers to the location in memory thatptr
points to while the value ofptr
itself is the address of that location) and++*ptr++
actually means:*ptr = *ptr + 1; ptr = ptr + 1;
- it increments the value pointed to byptr
and then increments the pointer value itself.i++
is not an lvalue since it is the value ofi
incremented by 1 and does not refer to a location in memory. You can think of such values as final - they cannot be further modified and can only be used as values to assign to lvalues. That's why they are called rvalues (from right-hand side (RHS) value).LHS and RHS refer to both sides of the assignment expression
A = B;
.A
is the LHS andB
is the RHS.From Deitel and Deitel:
Variable names are said to be lvalues (for "left values") because they can be used on the left side of an assignment operator. Constants are said to be rvalues (for "right values") because they can be used on only the right side of an assignment operator. Note that lvalues can also be used as rvalues, but not vice versa.