lvalues and rvalues

  • Thread starter Nicklas Karlsson
  • Start date
J

J de Boyne Pollard

You very nearly *can* tell whether an expression is an lvalue or
No, no, of course not.

Rephrasing:

You very nearly *can* tell
whether or not an expression is an lvalue
just by looking at it.

For what it's worth: Several authorities consider "whether or not"
to be synonymous with "whether", and the "or not" to be, as M.
Uno might have been enquiring, superfluous.
 
J

J de Boyne Pollard

(I just checked the C++ standard.  C++ definitely defines
"rvalue" differently than C does.  Its definition of
"lvalue" may or may not be consistent with C's.)

At this point, what the current C++ standard's definition
of the concept may be is less interesting than all of the
new concepts that were put into the FCD at the last
minute just recently. The FCD for the C++ Standard has
lvalues, rvalues, glvalues, xvalues, and prvalues.

I'd be interested in your views on those, given what
you wrote earlier in this thread.
 
T

Tim Rentsch

Eric Sosman said:
Well, that's one way to look at it, but I find it clearer to think of
an address (pointer value) as pointing to the entire object. It's one
way in which a C pointer value is conceptually different, and at a
higher level, than a machine address.

It seems to me that an int* could address any byte of an
int object (maybe even no byte at all), so long as the platform
knows how to get at the entire int given the int* value.
Converting to a char* must produce a pointer to the [0] element
of a sizeof(int)-byte array that overlays the int object, but
that's no obstacle: conversion need not be a bit-for-bit copy.

Here's a challenge: If an int* does *not* address the first
byte of an int object, can a portable[*] program detect the fact?
[snip explanation of "portable"]

This question has no answer because it has no meaning. In some
implementations we might say a particular pointer does or does
not address the first byte of the designated object, but there's
no way to give the phrase a meaning that makes sense in all
implementations. The notion of whether a pointer "addresses the
first byte of (some) object" just doesn't exist in the abstract
machine. Also apparently not in some actual machines either, but
what matters is whether such a notion exists in the abstract
machine, or, if one prefers, whether it _must_ exist in all
possible implementations on all possible machines. And the
answer to that question is just "no".
 
T

Tim Rentsch

Stephen Sprunk said:
A good point. A C pointer has a type, which implies a size; a machine
address does not have a type, so the particular instruction(s) that
use/manipulate that (typeless) address must imply the size of the
object. The compiler uses pointer type information to choose those
instructions, though...


True, at a C level, but is there really a difference at the machine
level on real-world implementations?

More importantly, assuming a T is a multi-byte object and pointers are
simple memory addresses, is it possible for &T to be the address of a
byte _other than_ the first (i.e. lowest) byte of the object?

Certainly it is. Didn't you just explain this yourself
in another posting a short time later (or was it earlier)?
 
T

Tim Rentsch

Phil Carmody said:
Seebs said:
Do such fat pointer implementations really exist, check a significant
proportion of the accesses, and compile real world code into something
that works? I can't see how a pointer to a single object in an array
would be distinguished from a pointer to the rest of the elements of
the array from that single object onwards.

I am told that such implementations exist, basically as extremely
elaborate instrumentation of code. It is certainly possible to make one
that correctly checks absolutely all accesses -- and even to make it
tolerably efficient by static analysis so you don't have to keep rechecking
things.
You (the caller) don't want fblag(FILE*fp,...) accessing fp[1], but
you don't mind strstuff(char*s,...) accesing s[1], s[2], ... . How
do you make that distinction?

When fp was returned from fopen, it was already tagged with the information
that it pointed to a single FILE. When you pass s in to strstuff(), it's
an existing pointer which was somehow derived from an object, or allocated,
or something. So we know its bounds.

Hmmm, what prevents...

static FILE __system_fps[3] = { /* populated in some system-specific way */ };

stdin = &__system_fps[0];
stdout = &__system_fps[1];
stderr = &__system_fps[2];

Technically 'stdin' is a macro. But it could be defined
thusly

#define stdin stdin
extern FILE *const stdin = &__system_fps[0];
/* etc */
 
T

Tim Rentsch

Keith Thompson said:
Joe Wright said:
I don't understand the 'very nearly' qualifier. Can we identify an
expression which designates an object by looking at it? How else?

Case 1:

int x;
/* The expression ``x'' is an lvalue. */

Case 2:

enum { x };
/* The expression ``x'' is not an lvalue. */

In many cases ("very nearly" may have been an overstatement), you can
tell whether a given expression is an lvalue or not just by looking at
it. ``*x'' and ``x[y]'' are lvalues; ``&x'' and ``2+2'' are not.

If we have

int x[10][20];

then 'x[y]' is not an lvalue.
 
T

Tim Rentsch

J de Boyne Pollard said:
For what it's worth: Several authorities consider "whether or not"
to be synonymous with "whether", and the "or not" to be, as M.
Uno might have been enquiring, superfluous.

In informal English, or in formal technical English?
What's appropriate in one might not be appropriate
in the other. In formal technical English, saying
"whether or not" clearly removes a possible ambiguity;
it also allows expressing a condition of being possible
to know that something IS something else, without always
being able to know that something ISN'T something else.
For example, we can know for sure that a given program has
no uninitialized variables, but we can't always know for
sure that a program _doesn't_ have uninitialized
variables.
 
S

SG

Tim said:
If we have

    int x[10][20];

then 'x[y]' is not an lvalue.

Not true. &x[y] is valid and yields a pointer of type int(*)[20].
Since the unary & requires an lvalue expression operand x[y] cannot be
an rvalue. In fact, it is an lvalue of type int[20]. Array-to-pointer
decay only happens if it's used in a context where an rvalue is
needed.

In C++ the behaviour is exactly the same and only more apparent in
combination with references and template argument deduction.

Cheers,
SG
 
T

Tim Rentsch

SG said:
Tim said:
If we have

int x[10][20];

then 'x[y]' is not an lvalue.

Not true. &x[y] is valid and yields a pointer of type int(*)[20].
Since the unary & requires an lvalue expression operand x[y] cannot be
an rvalue. In fact, it is an lvalue of type int[20]. Array-to-pointer
decay only happens if it's used in a context where an rvalue is
needed. [snip]

Of course what I meant was 'x[y]' as an expression by
itself is not an lvalue. In the context of '&x[y]'
the sub-expression 'x[y]' is an lvalue, but I was
speaking of 'x[y]' not in that context.

I don't mind being corrected, but please don't
deliberately misunderstand me to supply a
"correction".
 
K

Keith Thompson

Joe Wright said:
On 4/10/2010 00:00, Keith Thompson wrote: [...]
Case 1:

int x;
/* The expression ``x'' is an lvalue. */

Case 2:

enum { x };
/* The expression ``x'' is not an lvalue. */

In many cases ("very nearly" may have been an overstatement), you can
tell whether a given expression is an lvalue or not just by looking at
it. ``*x'' and ``x[y]'' are lvalues; ``&x'' and ``2+2'' are not.
So now 'many cases'. Can you give an example of an expression whose
'lvalueness' cannot be determined by simple inspection?

Look up a few lines. You see that expression ``x''? Can you
determine whether it's an lvalue by simple inspection?

Isn't that exactly what I was just saying?
 
E

Eric Sosman

Eric Sosman said:
[...]
Here's a challenge: If an int* does *not* address the first
byte of an int object, can a portable[*] program detect the fact?
[snip explanation of "portable"]

This question has no answer because it has no meaning. [...]

Very good! You've grasped my point, exactly!
 
E

Eric Sosman

If we have

int x[10][20];

then 'x[y]' is not an lvalue.

No, it *is* an lvalue (assuming a valid `y'). It's not a
"modifiable lvalue," but it's an lvalue. 6.3.2.1p1.
 
T

Tim Rentsch

Eric Sosman said:
If we have

int x[10][20];

then 'x[y]' is not an lvalue.

No, it *is* an lvalue (assuming a valid `y'). It's not a
"modifiable lvalue," but it's an lvalue. 6.3.2.1p1.

Surely you must know what I mean. The expression
'x[y]' is an array and as such it is converted to
a pointer to the array's first element and is no
longer an lvalue. 6.3.2.1p3.
 
K

Keith Thompson

Tim Rentsch said:
Eric Sosman said:
If we have

int x[10][20];

then 'x[y]' is not an lvalue.

No, it *is* an lvalue (assuming a valid `y'). It's not a
"modifiable lvalue," but it's an lvalue. 6.3.2.1p1.

Surely you must know what I mean. The expression
'x[y]' is an array and as such it is converted to
a pointer to the array's first element and is no
longer an lvalue. 6.3.2.1p3.

That conversion isn't always done.

Expressions never appear in isolation. Even in the statement
x[y];
the expression ``x[y]'' is part of an expression statement. There's
always some context, and that context determines whether or not the
conversion takes place.

Given the above declaration, if x[y] appears in a context in which
the conversion takes place, it's not an lvalue; otherwise, it is.
 
E

Eric Sosman

Eric Sosman said:
If we have

int x[10][20];

then 'x[y]' is not an lvalue.

No, it *is* an lvalue (assuming a valid `y'). It's not a
"modifiable lvalue," but it's an lvalue. 6.3.2.1p1.

Surely you must know what I mean.

Apparently not. I mistook your "`x[y] is not an lvalue"
to mean that `x[y]' is not an lvalue. Sorry about that.
The expression
'x[y]' is an array and as such it is converted to
a pointer to the array's first element and is no
longer an lvalue. 6.3.2.1p3.

... which has nothing to do with the lvalue-ness of the
expression `x[y]'. It talks of the non-lvalue-ness of a value
*derived from* that expression in some contexts (those not
covered by the paragraph's first phrase, which begins with the
telltale word "Except").
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
Eric Sosman said:
On 4/10/2010 12:49 PM, Tim Rentsch wrote:

If we have

int x[10][20];

then 'x[y]' is not an lvalue.

No, it *is* an lvalue (assuming a valid `y'). It's not a
"modifiable lvalue," but it's an lvalue. 6.3.2.1p1.

Surely you must know what I mean. The expression
'x[y]' is an array and as such it is converted to
a pointer to the array's first element and is no
longer an lvalue. 6.3.2.1p3.

That conversion isn't always done.

Expressions never appear in isolation. Even in the statement
x[y];
the expression ``x[y]'' is part of an expression statement. There's
always some context, and that context determines whether or not the
conversion takes place.

Given the above declaration, if x[y] appears in a context in which
the conversion takes place, it's not an lvalue; otherwise, it is.

Quite right. I'd already responded on this point, in
my followup to SG, so I didn't bother saying it
again.
 
T

Tim Rentsch

Eric Sosman said:
Eric Sosman said:
On 4/10/2010 12:49 PM, Tim Rentsch wrote:

If we have

int x[10][20];

then 'x[y]' is not an lvalue.

No, it *is* an lvalue (assuming a valid `y'). It's not a
"modifiable lvalue," but it's an lvalue. 6.3.2.1p1.

Surely you must know what I mean.

Apparently not. I mistook your "`x[y] is not an lvalue"
to mean that `x[y]' is not an lvalue. Sorry about that.
The expression
'x[y]' is an array and as such it is converted to
a pointer to the array's first element and is no
longer an lvalue. 6.3.2.1p3.

... which has nothing to do with the lvalue-ness of the
expression `x[y]'. It talks of the non-lvalue-ness of a value
*derived from* that expression in some contexts (those not
covered by the paragraph's first phrase, which begins with the
telltale word "Except").

It seems to me you're being deliberately obtuse. However, ignoring
that, your statement above is still at odds with the text in the
Standard. 6.3.2.1p3 (first sentence):

Except when it is the operand of the sizeof operator or the
unary & operator, or is a string literal used to initialize
an array, an expression that has type ``array of type'' is
converted to _an expression_ [emphasis added] with type
``pointer to type'' that points to the initial element of
the array object and is not an lvalue.

The Standard is talking about the lvalue-ness of an expression,
not of a value. Furthermore I think most C developers with some
exposure to the term 'lvalue' in it Standardese sense would say
the same thing -- given 'int x[10][20];', the expression 'x[10]'
doesn't behave the same way as a simple variable reference (which
is an lvalue), in that it doesn't designate an object, cause a
read access on the RHS of an assignment, etc[*] -- that is, it's
not an lvalue. Since the Standard agrees with my usage, and
since most other folks seem to know what I mean, your comments
left me rather baffled.


[*] Yes, for the nth time, whether 'x[10]' behaves as an
lvalue depends on context, such as '&x[10]' when it does.
My usage of 'x[10]' is meant to apply to the typical
cases, not the exceptional ones such as '&x[10]'.
 
K

Keith Thompson

Tim Rentsch said:
If we have

int x[10][20];

then 'x[y]' is not an lvalue.

On further thought, yes, it is, regardless of the context in which it
appears.

C99 6.5.2.1p2:

The definition of the subscript operator [] is that E1[E2] is
identical to (*((E1)+(E2))).

C99 6.5.3.2p4:

The unary * operator denotes indirection. If the operand points to
a function, the result is a function designator; if it points to
an object, the result is an lvalue designating the object.

And just for completeness, C99 6.5.1p5:

A parenthesized expression ... is an lvalue ... if the
unparenthesized expression is ... an lvalue.

(Please feel free to confirm that I haven't left out anything relevant
to this case.)

Unless I've missed something (which is always possible), if you want
to argue that it's not an lvalue, your argument is with the Standard.
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
If we have

int x[10][20];

then 'x[y]' is not an lvalue.

On further thought, yes, it is, regardless of the context in which it
appears.

C99 6.5.2.1p2:

The definition of the subscript operator [] is that E1[E2] is
identical to (*((E1)+(E2))).

C99 6.5.3.2p4:

The unary * operator denotes indirection. If the operand points to
a function, the result is a function designator; if it points to
an object, the result is an lvalue designating the object.

And just for completeness, C99 6.5.1p5:

A parenthesized expression ... is an lvalue ... if the
unparenthesized expression is ... an lvalue.

(Please feel free to confirm that I haven't left out anything relevant
to this case.)

Unless I've missed something (which is always possible), if you want
to argue that it's not an lvalue, your argument is with the Standard.

Please see my response to Eric Sosman. 6.3.2.1p3 seems pretty
clear that an expression with array type becomes (in most
contexts) an expression that is not an lvalue. And this agrees,
I think, with most people's intuition about what an lvalue is
(assuming of course that they're at least passingly familiar with
'lvalue' as it is used in the Standard).
 
S

SG

    Except when it is the operand of the sizeof operator or the
    unary & operator, or is a string literal used to initialize
    an array, an expression that has type ``array of type'' is
    converted to _an expression_ [emphasis added] with type
    ``pointer to type'' that points to the initial element of
    the array object and is not an lvalue.

The Standard is talking about the lvalue-ness of an expression,
not of a value.  Furthermore I think most C developers with some
exposure to the term 'lvalue' in it Standardese sense would say
the same thing -- given 'int x[10][20];', the expression 'x[10]'
doesn't behave the same way as a simple variable reference (which
is an lvalue), in that it doesn't designate an object, cause a
read access on the RHS of an assignment, etc[*] -- that is, it's
not an lvalue.  Since the Standard agrees with my usage, and
since most other folks seem to know what I mean, your comments
left me rather baffled.

When you say 'x[y]' is not an lvalue then you include this implicit
conversion and refer to the expression you get after the conversion.
When I said 'x[y]' is an lvalue I excluded this conditional implicit
conversion and referred to the expression before the implicit
conversion. I was probably as buffled as you are now when I got your
response where you accused me of "deliberately misunderstanding"
things. :)

In practice, these differing POVs don't matter in C. But they actually
do matter in C++ and the POV that x[y] is an lvalue just like x is an
lvalue allows you to get away with more regularity and fewer special
case rules. I guess you havn't read the C++ standard (which is where
I'm coming from) just like I just skimmed through the C standard for
the first time. I hereby admit that I didn't expect to see such
wording you can find in 3.2.1/3. That would at least explain the
situation.

Cheers,
SG
 

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

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top