Question

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?

Was it helpful?

Solution

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 that ptr points to while the value of ptr itself is the address of that location) and ++*ptr++ actually means: *ptr = *ptr + 1; ptr = ptr + 1; - it increments the value pointed to by ptr and then increments the pointer value itself. i++ is not an lvalue since it is the value of i 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 and B is the RHS.

OTHER TIPS

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:

64) The name ‘‘lvalue’’ comes originally from the assignment expression E1 = E2, in which the left operand E1 is required to be a (modifiable) lvalue. It is perhaps better considered as representing an object ‘‘locator value’’. What is sometimes called ‘‘rvalue’’ is in this International Standard described as the ‘‘value of an expression’’.

An obvious example of an lvalue is an identifier of an object. As a further example, if E is a unary expression that is a pointer to an object, *E is an lvalue that designates the object to which E points.

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):

An lvalue is an expression (with an object type other than void) that potentially designates an object;64) if an lvalue does not designate an object when it is evaluated, the behavior is undefined.

Also, note the next line which is important:

When an object is said to have a particular type, the type is specified by the lvalue used to designate the object.

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):

when it is the operand of the sizeof operator, the _Alignof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator

So, these are the operators that you need to keep an eye out for. In all other cases:

an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion.

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!)

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.

x = 3;  /*  here, x is an lvalue */
c = x;  /*  and in the next line it is an rvalue */
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top