[snip good examples]
It's conceptually simpler, IMHO, for lvalue-ness to depend on the
expression itself, not on the context in which it appears. An lvalue
is a kind of expression. ``2+2'' is an additive-expression,
and it continues to be an additive-expression even when used in
a context that doesn't require an additive-expression. ``obj''
is an lvalue, and it continues to be an lvalue even when used in a
context that doesn't require an lvalue. (And similarly, ``0'' is
both an octal-constant and a null pointer constant, regardless of
where it appears, even though some might find that counterintuitive.)
Now, you might think that "lvalue" isn't a good term for the
property needed here, and maybe that's right. However, I think
you'll agree that this property is an important property to
distinguish, and the current standard uses "lvalue" as the
term that identifies it[*]. So I think it's better to keep
using "lvalue" to identify those expressions that are legal
in contexts like the ones (on the left) shown above.
[*] Not counting some minor glitches in the current definition
of lvalue, which doesn't affect the basic point.
In a footnote on 'lvalue' the Standard explains the 'l' stands for left
operand of an assignment and might well stand for 'locator value'. It
mentions that 'rvalue' for Standard purposes is the 'value of an
expression'.
Footnote 53 in n1256 says:
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''.
The term "lvalue" predates the C Standard (indeed, it predates C
itself), and the footnote is explaining that historical origin,
not what the term means in the Standard. The second sentence
(starting "It is perhaps better considered...") makes a comment
about how "lvalue" should be understood as it is now used in
the Standard document.
As I understand it, the C standard's definition of lvalue, even
setting aside the glitches, is quite different from the original
meaning. We're stuck with the standard's meaning, but it's worth
exploring the original meaning.
In C, an lvalue is a particular kind of expression. Thus it's
something that exists in a program, and is recognized during
translation phase 7.
In the original meaning, as I understand it an lvalue is, as the name
implies, a kind of *value*, and an rvalue is another kind of value.
Note that expressions exist in a program, and values exist during
the execution of a program, so they're very different (but closely
related) things. A value is what you get during execution as
the result of evaluating an expression (something that exists in a
program and is recognized during TP7). The *expression* 42 consists
of a token, which in turn consists of the two source characters '4'
and '2'. When the expression is evaluated, it yields a *value*
that might be stored in, say, a 16-bit word as the bit pattern
0000000000101010; the '4' and the '2' no longer exist.
Using the non-C meanings of the terms, an expression can be
evaluated in one of two ways, depending on the context in which it
appears. In some contexts, particularly the LHS of an assignment,
an expression can be evaluated for its lvalue. The resulting value
is the identity of an object. In other contexts, particularly the
RHS of an assignment, an expression can be evaluated for its rvalue.
An rvalue is a value of some type; it might, for example, be the
result of retrieving the contents of an object, or of applying an
operator to one or more operands.
So given:
x = y;
the expression ``x'' is evaluated for its lvalue (in the non-C
sense), and the result is the identity of the object x; this is
unrelated to whatever value is currently stored in x. The expression
``y'' is evaluated for its rvalue, and the result is whatever value
is retrieved from the object y.
It's tempting to think of this non-C lvalue as an address, but it's
a different thing. An address, such as the result of ``&obj''
is an rvalue, not an lvalue. An lvalue isn't an address; it's
the identity of an object. An lvalue might identify a register
object or a bit field, neither of which has an address -- but they
do have identities.
If C had stuck with these meanings, then we'd say, not that some
expressions *are* lvalues, but that some expressions *have* lvalues.
An expression in certain contexts, such as the LHS of an assignment,
is evaluated for its lvalue. If the expression doesn't have an
lvalue, such as 42, then it's a constraint violation. If the
expression can be evaluated for its lvalue but the result doesn't
identify any object (such as *ptr where ptr==NULL), then the behavior
is undefined.
Given this formulation, it would be very handy to have a simple
term to refer to an expression that has an lvalue, so we could make
statements about what kind of expression is required on the LHS of
an assignment. Perhaps "l-expression".
But the term the authors of the C standard chose for this kind of
expression is "lvalue". And the standard keeps "rvalue" with its
original meaning ("the value of an expression"), but relegates it
to a footnote and doesn't use it.