lvalue and rvalue?

Z

Zach

int x;
x = 10;

here x is the lvalue (the object holding a value) and 10 is the rvalue
(the value being assigned to an object) correct?

zach
 
M

Magnus Brand

Zach said:
int x;
x = 10;

here x is the lvalue (the object holding a value) and 10 is the rvalue
(the value being assigned to an object) correct?

That's true. In K&R-2 it is stated that "An object is a named region of
storage; an lvalue is an expression referring to an object". So in your
example, 'x' is the expression and 10 the actual object.
An exception to this are arrays, since the name of an array itself is an
expression but can't be modified. So can refer to it as an "unmodofiable
lvalue".

Magnus
 
K

Keith Thompson

Zach said:
int x;
x = 10;

here x is the lvalue (the object holding a value) and 10 is the rvalue
(the value being assigned to an object) correct?

The meanings of the terms "lvalue" and "rvalue" can be tricky.

Before C existed, the terms "lvalue" and "rvalue" referred to two
different ways of evaluating an expression. The 'l' and 'r' stand for
"left" and "right", as in the left and right sides of an assignment
statement. Evaluating an expression for its lvalue meant determining
what object it designates. Evaluting an expression for its rvalue
meant determining the value of the expression.

For example, given the declaration "int x;" evaluating the expression
``x'' would mean determining the object to which it refers -- without
accessing that object's value. In an exprssion like arr[func() + 3],
this can involve more than just resolving a name. Evaluating the
expression ``x'' for its rvalue would mean accessing the object to
obtain the value stored in it. Some expressions, such as ``x + 1'',
cannot be evaluated for their lvalues, because they don't refer to any
object.

The C standard changed the way the term "lvalue" is used, and almost
entirely dropped the term "rvalue". In C, an "lvalue" is not the
result of evaluating an expression, it's the expression itself. The
only mention of "rlvalue" is in a footnote, which says that it just
means the value of an expression. An expression that's not an lvalue
isn't referred to as a rvalue; it's just a non-lvalue expression.

An lvalue in C is basically an expression that designates an object.
Just to add to the frivolity, the C89/C90 standard's definition of
"lvalue" was worded incorrectly, and the C99 standard's revised
definition attempted to correct it but just made a mess of the whole
thing. (The mess is the result of trying to nail down case like *ptr,
where ptr is a pointer that doesn't currently point to an object.
*ptr is still an lvalue, but trying to use it as one invokes undefined
behavior. In two attempts, the standard has failed to express that
correctly.)

So in your statement:
x = 10;
the subexpression x is an lvalue, and is used as an lvalue, because it
designates the object named "x".

Given:

int x;
int y = 10;
x = y;

In the assignment, both subexpressions x and y are lvalues, because
they're both expressions that designate objects. But y is not being
used as an lvalue; it's in a context, the right hand side of an
assignment, that doesn't require an lvalue. So the fact that it's an
lvalue is incidental. The left side of an assignment is a context
that does require an lvalue, so this:

(x + 1) = y;

is illegal (a constraint violation).

Sorry to have to give such a long explanation, but your question
wasn't as simple as it appeared (or as it should be).
 
K

Keith Thompson

Magnus Brand said:
That's true. In K&R-2 it is stated that "An object is a named region
of storage; an lvalue is an expression referring to an object".

So x is an lvalue, but an lvalue is an expression, not an object.
So in
your example, 'x' is the expression and 10 the actual object.

'x', '10', and 'x = 10' are all expressions. 10 is not an object.
An exception to this are arrays, since the name of an array itself is
an expression but can't be modified. So can refer to it as an
"unmodofiable lvalue".

Right, an array name is an unmodifiable lvalue. (An array *object* is
not an lvalue; it's an object.)
 
M

Magnus Brand

Keith said:
> So x is an lvalue, but an lvalue is an expression, not an object.
> 10 is not an object.
I never said an lvalue was an object.
But why isn't '10' an object? I thought a data object was just a region
in memory that contains one value (or several values). So you've got a,
e.g. 4 bytes long memory section that holds this value.

I bid for rectification.

Magnus
 
K

Keith Thompson

Magnus Brand said:
I never said an lvalue was an object.

The original poster more or less did:

here x is the lvalue (the object holding a value)
But why isn't '10' an object? I thought a data object was just a
region in memory that contains one value (or several values). So
you've got a, e.g. 4 bytes long memory section that holds this value.

Objects have addresses.

The context was an assignment:

x = 10;

An "object" is, by definition, a "region of data storage in the
execution environment, the contents of which can represent values".
10 is a value, not an object. It's not necessarily stored in memory.
In particular, it has no address.

An implementation might choose to store it in memory, but that's an
implementation detail that doesn't affect the question of whether it
can formally be considered to be an object. For example, the CPU
might have a "store ten in specified location" instruction.
 
J

James Kuyper

Magnus said:
I never said an lvalue was an object.
But why isn't '10' an object? I thought a data object was just a region
in memory that contains one value (or several values). So you've got a,
e.g. 4 bytes long memory section that holds this value.

The key point is that use of the integer literal 10 does not actually
require that a piece of memory be set aside to store a value of 10. If
you write 10*x, an implementation could just build that value (directly
or indirectly) into the executable code that performs the multiplication.

For instance, I've heard that there are some implementations which might
(under the right circumstances) generate code for 10*x which would be
equivalent to 8*x+2*x, or in other words, x<<3 + x<<1. On the hardware
these implementations were intended for, the two shifts and the addition
execute faster than the multiply, and the equivalent of the '3' and the
'1' are stored directly as part of the shift instruction. Its been so
long since I heard this that I can't remember what the target hardware
was; and it's quite possible that there are no longer any machines where
this would be a good idea; but that's irrelevant to my point. Even if
there were no such implementation, it would still be the case that such
an implementation would be perfectly conforming, and that IS my point.
 
I

Ian Collins

Magnus said:
I never said an lvalue was an object.
But why isn't '10' an object? I thought a data object was just a region
in memory that contains one value (or several values). So you've got a,
e.g. 4 bytes long memory section that holds this value.
In addition to Keith's points, how do you propose assigning a value to '10'?
 
S

Stephen Sprunk

James said:
For instance, I've heard that there are some implementations which might
(under the right circumstances) generate code for 10*x which would be
equivalent to 8*x+2*x, or in other words, x<<3 + x<<1. On the hardware
these implementations were intended for, the two shifts and the addition
execute faster than the multiply, and the equivalent of the '3' and the
'1' are stored directly as part of the shift instruction. Its been so
long since I heard this that I can't remember what the target hardware
was; and it's quite possible that there are no longer any machines where
this would be a good idea; but that's irrelevant to my point. Even if
there were no such implementation, it would still be the case that such
an implementation would be perfectly conforming, and that IS my point.

Actually, turning multiplication and division by a constant into
shifting, addition, and/or subtraction is a very common optimization, or
at least the base of one.

For example, GCC turns "y = x * 10" into the following on my machine:

y = x;
y <<= 2;
y += x;
y += y;

That's pretty clever for "no" optimization. If I turn it up a notch:

y = x*4 + x;
y += y;

(x86's LEA instruction can do a*b+c iff b is a constant power of two.
It's really a fused shift-add instruction, not a fused multiply-add, but
convention is to write it as a multiply-add.)

S
 
M

Magnus Brand

Ian said:
In addition to Keith's points, how do you propose assigning a value to '10'?
You can't because as a it's always an rvalue, I'd say. Assignments are
the reason why lvalues exist.

Magnus
 
P

Phil Carmody

Keith Thompson said:
The original poster more or less did:

here x is the lvalue (the object holding a value)


Objects have addresses.

The context was an assignment:

x = 10;

An "object" is, by definition, a "region of data storage in the
execution environment, the contents of which can represent values".
10 is a value, not an object. It's not necessarily stored in memory.
In particular, it has no address.

But c.f.
register int x=10; /* x also isn't /necessarily/ stored in memory */

However that example doesn't contradict the quoted definition in any way.
An implementation might choose to store it in memory, but that's an
implementation detail that doesn't affect the question of whether it
can formally be considered to be an object. For example, the CPU
might have a "store ten in specified location" instruction.

And in fact some of the less brain-dead architectures I've
worked with do.

Phil
 
K

Keith Thompson

Phil Carmody said:
Objects have addresses. [...]

The context was an assignment:

x = 10;

An "object" is, by definition, a "region of data storage in the
execution environment, the contents of which can represent values".
10 is a value, not an object. It's not necessarily stored in memory.
In particular, it has no address.

But c.f.
register int x=10; /* x also isn't /necessarily/ stored in memory */

However that example doesn't contradict the quoted definition in any way.

Good point. My statement that "Objects have addresses." was an
over-generalization. Bit fields are another exception.

"data storage" is not necessarily addressible memory.

[...]
 
C

CBFalconer

James said:
.... snip ...

For instance, I've heard that there are some implementations which
might (under the right circumstances) generate code for 10*x which
would be equivalent to 8*x+2*x, or in other words, x<<3 + x<<1. On
the hardware these implementations were intended for, the two
shifts and the addition execute faster than the multiply, and the
equivalent of the '3' and the '1' are stored directly as part of
the shift instruction. ...

That's just a means of implementing the multiply. The basic
requirements, to ensure it is worthwhile, is that one of the
operands is a constant, and that that operand can be represented as
the sum or difference of two binary powers. For example, if the
constant in binary is 0000011100 that can be represented by (32 *
OP2) - (4 * OP2), and the 32 and 4 are achieved by shifting.
Similarly 0001000010 is represented by (2 * OP2) + (64 * OP2).
Very useful when the machinery has no multiply instruction, and a
routine must be called. To keep the number of shifts down, just
insist the multiplier is less than some suitable constant before
generating that code.
 
K

Kaz Kylheku

You can't because as a it's always an rvalue, I'd say. Assignments are
the reason why lvalues exist.

You can use lvalues to access objects. Or to take the address which is later
used perhaps only for accessing, and not modifying.

Lvalues don't even have to be modifiable, and only the modifiable ones
can be assigned to.

An expression that designates an array is an lvalue. Does that exist
for the sake of assigning to an array?
 
K

Kaz Kylheku

I don't recommend that the OP listen to Keith Thompson. He's had
a habit in recent days of making erroneous statements. Or maybe it's
just that I've decided to start pointing them out.

If objects are guaranteed addresses, then the standard wouldn't take
pains to use the phrase "non-bitfield objects".

You're looking too hard. Your points are easily supported by the
definitions section.
take pains to make certain exceptions for objects declared with the
storage-class specifier 'register'.

3.5 bit: unit of data storage in the execution environment large enough
to hold an object that may have one of two values.

3.14 object: region of data storage in the execution environment,
the contents of which can represent values.

I seem to recall C90 objects being addressable by definition, but that's
clearly not the case now.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top