lvalues and rvalues

  • Thread starter Nicklas Karlsson
  • Start date
N

Nicklas Karlsson

Hello,

I am quite confused about this, so I split it in to subquestions, here
we go:

1. Is an lvalue the expression itself, or is it the result yielded by
evaluation of an expression? Take this for example: int i = 10; int *p
= &i; and then dereference: *p; is the expression "*p" the thing you
call an lvalue or is an lvalue the result yielded by evaluating that
lvalue-expression?

2. Rvalues, is rvalues the result yielded by an rvalue-expression, or
is it the expression itself? If its the result yielded by evaluation
of an rvalue-expression is an rvalue a plain value?

3. I am quite sure that in a conversion from C to Assembly an lvalue-
expression yields an an address when evaluated, however, in C an
lvalue seems to have properties, an address and a type, again, using
the example of *p, the lvalue will be of type "int", if an lvalue-
expression always yields an address when evaluated, C could keep track
of the addresses type, so if the lvalue (the address) is "0x0" and C
knows the addresses type is "int*" does C everytime it encounters that
lvalue say "here you can only read/write an int because the address is
int*" and therefor the type of the lvalue is "int"? But if its just an
address how can it have a type other then the addresses type? That
makes me wonder what an lvalue acctually is in C, how should I think
about it? It's something that keeps track of an address and type?

Kind regards // Nicklas
 
J

John Bode

Hello,

I am quite confused about this, so I split it in to subquestions, here
we go:

1. Is an lvalue the expression itself, or is it the result yielded by
evaluation of an expression? Take this for example: int i = 10; int *p
= &i; and then dereference: *p; is the expression "*p" the thing you
call an lvalue or is an lvalue the result yielded by evaluating that
lvalue-expression?

The expression is the lvalue (quoting H&S: "An lvalue is an expression
that refers to an object in such a way that the object may be examined
or altered."). So i, p, and *p are all lvalues, while &i and 10 are
not.
2. Rvalues, is rvalues the result yielded by an rvalue-expression, or
is it the expression itself? If its the result yielded by evaluation
of an rvalue-expression is an rvalue a plain value?

Again, it refers to the expression. Any expression that cannot be an
lvalue is an rvalue.
3. I am quite sure that in a conversion from C to Assembly an lvalue-
expression yields an an address when evaluated, however, in C an
lvalue seems to have properties, an address and a type, again, using
the example of *p, the lvalue will be of type "int", if an lvalue-
expression always yields an address when evaluated, C could keep track
of the addresses type, so if the lvalue (the address) is "0x0" and C
knows the addresses type is "int*" does C everytime it encounters that
lvalue say "here you can only read/write an int because the address is
int*" and therefor the type of the lvalue is "int"? But if its just an
address how can it have a type other then the addresses type? That
makes me wonder what an lvalue acctually is in C, how should I think
about it? It's something that keeps track of an address and type?

Kind regards // Nicklas

You're overthinking things a bit. The distinction between lvalues and
rvalues has mostly to do with what legally may be the target of an
assignment; type is a separate issue.

For example, if the type of x is long, then the type of x++ is also
long, but x++ is not an lvalue.
 
K

Keith Thompson

Nicklas Karlsson said:
I am quite confused about this, so I split it in to subquestions, here
we go:

Yes, it's confusing. The C standard's definitions of "lvalue" and
"rvalue" aren't necessarily consistent with their historical usage.
1. Is an lvalue the expression itself, or is it the result yielded by
evaluation of an expression? Take this for example: int i = 10; int *p
= &i; and then dereference: *p; is the expression "*p" the thing you
call an lvalue or is an lvalue the result yielded by evaluating that
lvalue-expression?

An "lvalue" is, roughly, an expression that designates an object.
(The C90 and C99 standard both managed to get the definition
seriously wrong, but that's the gist of it.)
2. Rvalues, is rvalues the result yielded by an rvalue-expression, or
is it the expression itself? If its the result yielded by evaluation
of an rvalue-expression is an rvalue a plain value?

A footnote in the standard says

What is sometimes called ‘‘rvalue’’ is in this International
Standard described as the ‘‘value of an expression’’.

So an lvalue is a kind of expression, and an rvalue is the
value that results from evaluating an expression.
3. I am quite sure that in a conversion from C to Assembly an lvalue-
expression yields an an address when evaluated, however, in C an
lvalue seems to have properties, an address and a type, again, using
the example of *p, the lvalue will be of type "int", if an lvalue-
expression always yields an address when evaluated, C could keep track
of the addresses type, so if the lvalue (the address) is "0x0" and C
knows the addresses type is "int*" does C everytime it encounters that
lvalue say "here you can only read/write an int because the address is
int*" and therefor the type of the lvalue is "int"? But if its just an
address how can it have a type other then the addresses type? That
makes me wonder what an lvalue acctually is in C, how should I think
about it? It's something that keeps track of an address and type?

An lvalue is not an address, though it's a related concept. An lvalue
doesn't point to an object, it "designates" an object.

For example, given

int x;

the expression ``x'' is an lvalue. It refers to the object x, not to
the address of that object (that would be ``&x'', which is *not* an
lvalue).

Whether an expression is an lvalue or not is relevant only in some
contexts, namely those contexts that require an lvalue. The most
obvious example is the left side of an assignment. For example:

x = 42;

is valid, because x is an value, but

41 = 42;

is not, because 41 is not an lvalue. The right hand side needn't be
an lvalue; only the *value* of the RHS is needed. But the left hand
side must designate an object

<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf> is the
latest post-C99 draft; it includes the material from the C99 standard
plus the three Technical Corrigenda. Section 6.3.2.1 discusses
lvalues. Be aware that the definition of the term in the first
paragraph is flawed, but it's otherwise a good explanation.
 
N

Nicklas Karlsson

Yes, it's confusing.  The C standard's definitions of "lvalue" and
"rvalue" aren't necessarily consistent with their historical usage.


An "lvalue" is, roughly, an expression that designates an object.
(The C90 and C99 standard both managed to get the definition
seriously wrong, but that's the gist of it.)


A footnote in the standard says

    What is sometimes called ‘‘rvalue’’ is in this International
    Standard described as the ‘‘value of an expression’’.

So an lvalue is a kind of expression, and an rvalue is the
value that results from evaluating an expression.


An lvalue is not an address, though it's a related concept.  An lvalue
doesn't point to an object, it "designates" an object.

For example, given

    int x;

the expression ``x'' is an lvalue.  It refers to the object x, not to
the address of that object (that would be ``&x'', which is *not* an
lvalue).

Whether an expression is an lvalue or not is relevant only in some
contexts, namely those contexts that require an lvalue.  The most
obvious example is the left side of an assignment.  For example:

    x = 42;

is valid, because x is an value, but

    41 = 42;

is not, because 41 is not an lvalue.  The right hand side needn't be
an lvalue; only the *value* of the RHS is needed.  But the left hand
side must designate an object

<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf> is the
latest post-C99 draft; it includes the material from the C99 standard
plus the three Technical Corrigenda.  Section 6.3.2.1 discusses
lvalues.  Be aware that the definition of the term in the first
paragraph is flawed, but it's otherwise a good explanation.

--
Keith Thompson (The_Other_Keith) (e-mail address removed)  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

Im not sure I follow, an rvalue is the value of an expression, its not
an expression? While an lvalue is an expression? But an lvalue is an
expression that does not evaluate to an rvalue? And since an lvalue is
an expression it evaluates to something, what exactly does it evaluate
to? Something that has a designated object and has a type? I read that
PDF and it said: "if an lvalue does not designate an object when it is
evaluated..." so it is something that designates an object? Am I
thinking wrong? And the expression does evaluate to an address? I read
this: http://accu.org/index.php/journals/227 it sorta says "every
expression yields either an lvalue or an rvalue and accordingly every
expression is called either an lvalue or an rvalue expression." that
is wrong, well it appears to be right now anyhow?
 
M

Morris Keesan

int x; ....
Whether an expression is an lvalue or not is relevant only in some
contexts, namely those contexts that require an lvalue. The most
obvious example is the left side of an assignment. For example:
x = 42;
is valid, because x is an value

[obviously a slip of the keyboard, and intended to read "x is an lvalue"].

The other obvious example of a context that requires an lvalue is the
operand of the unary & operator. An lvalue is something that has an
address, so

&x

is a valid expression, while

&42

is not. Given

const int y = 42;

y is an lvalue, so &y is a valid expression, while &42 is not, even though
y cannot appear on the left side of an assignment operator (because it's
an unmodifiable lvalue).
 
K

Keith Thompson

Nicklas Karlsson said:
Im not sure I follow, an rvalue is the value of an expression, its not
an expression? While an lvalue is an expression?

Yes, given the way the C standard defines the terms.
But an lvalue is an
expression that does not evaluate to an rvalue?

No.

Keep in mind that the C standard doesn't generally use the term
"rvalue". The only two occurences of the term are in that footnote
and in the corresponding index entry. If you're discussing C, it's
best to avoid the term "rvalue" altogether.

If an lvalue (a kind of expression) appears in a context that requires
an lvalue, it doesn't yield a result in the ordinary sense; rather, it
serves to designate (or identify) the object that's required in that
context. If it appears on the LHS of an assignment operator, it
designates the object to which a value is to be assigned. If it
appears as the operand of a unary "&" operator, it designates the
object whose address is taken. And so forth.

If an lvalue appears in a context that *doesn't* require an lvalue, it
yields an ordinary value -- specifically, it yields the stored value
of the object that it designates.

Thus:

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

In the assignment, both ``x'' and ''y'' are lvalues. Since ``x'' is
in a context that requires an lvalue, it identifies the object to be
written to (the previous value of that object, 10, is ignored). Since
''y'' is in a context that *doesn't* require an lvalue, it yields the
value (20) stored in the object that it designates (y).

(I'm using ``y'' to refer to the expression consisting of the
identifier y and just y to refer to the object. This isn't a standard
typographical convention, just the one I'm using here.)
And since an lvalue is
an expression it evaluates to something, what exactly does it evaluate
to?

It depends on the context; see above.
Something that has a designated object and has a type? I read that
PDF and it said: "if an lvalue does not designate an object when it is
evaluated..." so it is something that designates an object? Am I
thinking wrong?

An lvalue is an expression that designates an object.

Actually, that's not *quite* accurate. Given:
int *ptr = NULL;
the expression *ptr is an lvalue, even though it doesn't happen to
refer to any object at run time. This is the subtlety that has
tripped up the authors of the standard in trying to define the term.
(I won't go into the gory details yet again unless you really want me
to.)

What the standard probably should say is "if an lvalue does not
designate an object when it is evaluated *in a context that requires
an lvalue*, the behavior is undefined. And the definition should say
something along the lines that an lvalue is an expression that
*potentially* designates an object.

Given:

int x = 42;
int *ptr;

the expressions ``x'' and` ``*ptr'' are both lvalues. ``x''
unconditionally designates an object. ``*ptr'' may or may not
designate an object, depending on the value currently stored in
ptr; this is where the potential for undefined behavior comes in.
``42'' cannot possibly designate an object and is not an lvalue,
so an attempt to use it in a context requiring an lvalue will be
flagged at compile time.
And the expression does evaluate to an address?

No. Evaluating an lvalue in a context that requires an lvalue
identifies an object. It doesn't yield the object's address. It
could well be implemented by computing the object's address, but
consider this:
register int reg;
reg = 42;
The object reg has no address, but ``reg'' nevertheless designates
that object. The same applies to bit fields, which also have no
address.
I read
this: http://accu.org/index.php/journals/227 it sorta says "every
expression yields either an lvalue or an rvalue and accordingly every
expression is called either an lvalue or an rvalue expression." that
is wrong, well it appears to be right now anyhow?

It "sorta says"? Actually, you quoted the exact words, but you
didn't quote the beginning of the sentence:

*In C++* every expression yields either an lvalue or an rvalue and
accordingly every expression is called either an lvalue or an
rvalue expression.

I think that C++ defines the terms differently than C does. For
information on C++, see elsewhere.

I mentioned that the C standard doesn't use the traditional meanings
of the terms. I'll summarize my understanding of what those
traditional meanings are.

In a very simple language without objects, each expression yields a
value when evaluated. ``2 + 2'' yields the value 4, for example.

Once you introduce objects, assuming you want to treat assignments as
expressions, there are two possible ways to evaluate an expression.
You can either evaluate it to determine its value (``2 + 2'' yields
4, ``x + 3'' yields 45 if you've previously stored the value 42 in
x) *or* you can evaluate it to determine what object it designates,
ignoring any value that might be stored in that object. Which of
these things happens depends on the context in which the expression
appears. Traditionally, the former is referred to as "evaluating
an expression for its rvalue", and the latter as "evaluating an
expression for its lvalue". An rvalue is just an ordinary value of
some type. An lvalue is something that, rather than being a *value*
of some type, identifies an *object* of some type. The traditional
terminology unifies these two things (having a value vs. identifying
an object) into the single concept of "value", divided into "rvalue"
and "lvalue". The names of course come from the contexts in which
they appear, the right side vs. the left side of an assignment.

Note that some expressions, such as ``2 + 2'' cannot be evaluated for
their lvalues. (In C terms, ``2 + 2'' is not an lvalue.)

The authors of the C standard chose to drop the concept of "rvalue"
(other than a brief mention in a footnote which matches the
traditional meaning) and redefine "lvalue" as a kind of expression
rather than as the result of evaluating such an expression.

I'm sorry this is so long; I didn't have time to make it shorter.
 
B

bartc

Nicklas Karlsson said:
Hello,

I am quite confused about this, so I split it in to subquestions, here
we go:

1. Is an lvalue the expression itself, or is it the result yielded by
evaluation of an expression? Take this for example: int i = 10; int *p
= &i; and then dereference: *p; is the expression "*p" the thing you
call an lvalue or is an lvalue the result yielded by evaluating that
lvalue-expression?

A rule of thumb might be: if you can apply the & operator to it
(address-of), then it can be an lvalue (with a few exceptions such as
function names)

But here:

int A,B;

A = B;

Both A,B could be lvalues, but only A is being used as one. (In assembly,
you will find little difference between how the two are treated:

mov [A], # assuming memory-to-memory allowed

(I'm done a bit of compiler work; I would handle the assignment above as
follows:

*(&A) = B;

Ie. apply address-of to the left-hand-side, then dereference. The * and &
cancel out, but it has now verified the left-side is an lvalue. If you try
and write:

56 = B;

this obviously won't work (since &56 is not allowed).)
2. Rvalues, is rvalues the result yielded by an rvalue-expression, or
is it the expression itself? If its the result yielded by evaluation
of an rvalue-expression is an rvalue a plain value?

There will be some technical interpretation somewhere or other. To me, the
rvalue would be the result of evaluating the expression: a value with a
type. (In some languages, this is not quite so clear-cut; fortunately this
is C.)
3. I am quite sure that in a conversion from C to Assembly an lvalue-
expression yields an an address when evaluated,

Try looking at some assembly output.
however, in C an
lvalue seems to have properties, an address and a type, again, using
the example of *p, the lvalue will be of type "int", if an lvalue-
expression always yields an address when evaluated, C could keep track
of the addresses type, so if the lvalue (the address) is "0x0" and C
knows the addresses type is "int*" does C everytime it encounters that
lvalue say "here you can only read/write an int because the address is
int*" and therefor the type of the lvalue is "int"? But if its just an
address how can it have a type other then the addresses type? That
makes me wonder what an lvalue acctually is in C, how should I think
about it? It's something that keeps track of an address and type?

int A=78;

Here, several things are happening:

'A' A is really the name of a location, or address, containing 78.
Let's say this is address 0x400100.
The type of 'A' is pointer-to-int. However, C automatically
dereferences such names (in common with other languages), so:

A Will dereference the 'A' address with value 0x400100, to fetch
the value 78. This is now type int.

&A This overrides the automatic dereference to allow access to the
address. The value is 0x400100 with type pointer-to-int.

Which of this is an lvalue? Well A *can* be an lvalue, because you
can use & on it to obtain it's address (0x400100), allowing you to
store another value in there:

A = 79;

But I don't think an lvalue is specifically the address of something. Here:

enum {C=12};

'C' is the name of a constant value '12'. There is no address, and
therefore it can't be an lvalue. The type I would guess is just int.
 
N

Nicklas Karlsson

[...]
Im not sure I follow, an rvalue is the value of an expression, its not
an expression? While an lvalue is an expression?

Yes, given the way the C standard defines the terms.
                                                 But an lvalue is an
expression that does not evaluate to an rvalue?

No.

Keep in mind that the C standard doesn't generally use the term
"rvalue".  The only two occurences of the term are in that footnote
and in the corresponding index entry.  If you're discussing C, it's
best to avoid the term "rvalue" altogether.

If an lvalue (a kind of expression) appears in a context that requires
an lvalue, it doesn't yield a result in the ordinary sense; rather, it
serves to designate (or identify) the object that's required in that
context.  If it appears on the LHS of an assignment operator, it
designates the object to which a value is to be assigned.  If it
appears as the operand of a unary "&" operator, it designates the
object whose address is taken.  And so forth.

If an lvalue appears in a context that *doesn't* require an lvalue, it
yields an ordinary value -- specifically, it yields the stored value
of the object that it designates.

Thus:

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

In the assignment, both ``x'' and ''y'' are lvalues.  Since ``x'' is
in a context that requires an lvalue, it identifies the object to be
written to (the previous value of that object, 10, is ignored).  Since
''y'' is in a context that *doesn't* require an lvalue, it yields the
value (20) stored in the object that it designates (y).

(I'm using ``y'' to refer to the expression consisting of the
identifier y and just y to refer to the object.  This isn't a standard
typographical convention, just the one I'm using here.)
                                                And since an lvalue is
an expression it evaluates to something, what exactly does it evaluate
to?

It depends on the context; see above.
    Something that has a designated object and has a type? I read that
PDF and it said: "if an lvalue does not designate an object when it is
evaluated..." so it is something that designates an object? Am I
thinking wrong?

An lvalue is an expression that designates an object.

Actually, that's not *quite* accurate.  Given:
    int *ptr = NULL;
the expression *ptr is an lvalue, even though it doesn't happen to
refer to any object at run time.  This is the subtlety that has
tripped up the authors of the standard in trying to define the term.
(I won't go into the gory details yet again unless you really want me
to.)

What the standard probably should say is "if an lvalue does not
designate an object when it is evaluated *in a context that requires
an lvalue*, the behavior is undefined.  And the definition should say
something along the lines that an lvalue is an expression that
*potentially* designates an object.

Given:

    int x = 42;
    int *ptr;

the expressions ``x'' and` ``*ptr'' are both lvalues.  ``x''
unconditionally designates an object.  ``*ptr'' may or may not
designate an object, depending on the value currently stored in
ptr; this is where the potential for undefined behavior comes in.
``42'' cannot possibly designate an object and is not an lvalue,
so an attempt to use it in a context requiring an lvalue will be
flagged at compile time.
                And the expression does evaluate to an address?

No.  Evaluating an lvalue in a context that requires an lvalue
identifies an object.  It doesn't yield the object's address.  It
could well be implemented by computing the object's address, but
consider this:
    register int reg;
    reg = 42;
The object reg has no address, but ``reg'' nevertheless designates
that object.  The same applies to bit fields, which also have no
address.
                                                                I read
this:http://accu.org/index.php/journals/227it sorta says "every
expression yields either an lvalue or an rvalue and accordingly every
expression is called either an lvalue or an rvalue expression." that
is wrong, well it appears to be right now anyhow?

It "sorta says"?  Actually, you quoted the exact words, but you
didn't quote the beginning of the sentence:

    *In C++* every expression yields either an lvalue or an rvalue and
    accordingly every expression is called either an lvalue or an
    rvalue expression.

I think that C++ defines the terms differently than C does.  For
information on C++, see elsewhere.

I mentioned that the C standard doesn't use the traditional meanings
of the terms.  I'll summarize my understanding of what those
traditional meanings are.

In a very simple language without objects, each expression yields a
value when evaluated.  ``2 + 2'' yields the value 4, for example.

Once you introduce objects, assuming you want to treat assignments as
expressions, there are two possible ways to evaluate an expression.
You can either evaluate it to determine its value (``2 + 2'' yields
4, ``x + 3'' yields 45 if you've previously stored the value 42 in
x) *or* you can evaluate it to determine what object it designates,
ignoring any value that might be stored in that object.  Which of
these things happens depends on the context in which the expression
appears.  Traditionally, the former is referred to as "evaluating
an expression for its rvalue", and the latter as "evaluating an
expression for its lvalue".  An rvalue is just an ordinary value of
some type.  An lvalue is something that, rather than being a *value*
of some type, identifies an *object* of some type.  The traditional
terminology unifies these two things (having a value vs. identifying
an object) into the single concept of "value", divided into "rvalue"
and "lvalue".  The names of course come from the contexts in which
they appear, the right side vs. the left side of an assignment.

Note that some expressions, such as ``2 + 2'' cannot be evaluated for
their lvalues.  (In C terms, ``2 + 2'' is not an lvalue.)

The authors of the C standard chose to drop the concept of "rvalue"
(other than a brief mention in a footnote which matches the
traditional meaning) and redefine "lvalue" as a kind of expression
rather than as the result of evaluating such an expression.

I'm sorry this is so long; I didn't have time to make it shorter.

--
Keith Thompson (The_Other_Keith) (e-mail address removed)  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

Thanks for the reply guys!

So an lvalue does NOT evaluate in a traditional sense (yield a value)
but its being EVALUATED, so that the compiler can identify an object
and a size, the result of the evaluation specifies an object and a
type (and an object is a memory address right?) so if its on the left
side of assignenment it tells the compiler where to put the rvalue and
how much it can put, and if it appears on the right hand of assignment
it tells the compiler where to read the rvalue and how much to read?
Then you confuse me :)P) and say "and the latter as 'evaluating an
expression for its lvalue'", I thought we establised that the
expression itself was the lvalue?

In this: http://publib.boulder.ibm.com/infoc...ibm.vacpp6m.doc/language/ref/clrc05lvalue.htm
they call rvalues expressions too, but that is faulty (as the C-
standard says its a value of an expression), it may only apply to C++?
It also says: "When an lvalue appears in a context that requires an
rvalue, the lvalue is implicitly converted to an rvalue." that just
means that it starts to reads the rvalue at the address the lvalue
identifies? The lvalue is still evaluated right?

See I dont have a C-bot but a C++-bot and it shows precedence like
this ((*p) = 5); for *p = 5; and the (*p) must show that its being
evaluated right? But it shows i = 5; as (i = 5) but both are
expressions so I dont get why precedence differs?
 
K

Keith Thompson

Nicklas Karlsson said:
Thanks for the reply guys!

When you post a followup, please trim any quoted material that isn't
necessary. In particular, please don't quote signatures.
So an lvalue does NOT evaluate in a traditional sense (yield a value)
but its being EVALUATED, so that the compiler can identify an object
and a size,

Yes, but I wouldn't place so much emphasis on the size.

An lvalue (which is an expression) is of a particular type (and the
size is an attribute of that type). It identifies an object, which is
treated as being of that type. Usually that's going to be the
declared typethe object. If it's not (say, if there are pointer
conversions involved), then the type of the lvalue is what determines
the behavior.

A silly example:

int n;
*(unsigned int*)&n = 43;

Here n is declared to be of type int, but the lvalue
*(unsigned int*)&n
is of type unigsned int.
the result of the evaluation specifies an object and a
type (and an object is a memory address right?)

An object is, by definition, a "region of data storage in the
execution environment, the contents of which can represent values"
(C99 3.14). An object is not an address; an object (usually) *has* an
address.
so if its on the left
side of assignenment it tells the compiler where to put the rvalue and
how much it can put,

It tells the compiler the identify and type of the object into which
the value is to be stored. Remember I suggested avoiding the term
"rvalue"; the value to be stored is the value resulting from the
evaluation of the RHS expression.
and if it appears on the right hand of assignment
it tells the compiler where to read the rvalue and how much to read?

If an lvalue appears as the RHS of an assignment, it's just evaluated,
yielding the value stored in the designated object.
Then you confuse me :)P) and say "and the latter as 'evaluating an
expression for its lvalue'", I thought we establised that the
expression itself was the lvalue?

In C terms, yes. As I said, the C standard assigns a non-traditional
meaning to the term "lvalue". In C, the expression itself is the
lvalue.
In this: http://publib.boulder.ibm.com/infoc...ibm.vacpp6m.doc/language/ref/clrc05lvalue.htm
they call rvalues expressions too, but that is faulty (as the C-
standard says its a value of an expression), it may only apply to C++?
It also says: "When an lvalue appears in a context that requires an
rvalue, the lvalue is implicitly converted to an rvalue." that just
means that it starts to reads the rvalue at the address the lvalue
identifies? The lvalue is still evaluated right?

You're asking about C++ in a C newsgroup. lvalue-to-rvalue conversion
is a C++ concept, not a C concept. C++ has its own set of newsgroups
(and FAQs, which you should check before posting).

(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.)
See I dont have a C-bot but a C++-bot and it shows precedence like
this ((*p) = 5); for *p = 5; and the (*p) must show that its being
evaluated right? But it shows i = 5; as (i = 5) but both are
expressions so I dont get why precedence differs?

Precedence has nothing to do with it.
 
N

Nicklas Karlsson

You're asking about C++ in a C newsgroup.  lvalue-to-rvalue conversion
is a C++ concept, not a C concept.  C++ has its own set of newsgroups
(and FAQs, which you should check before posting).

Sorry, from the looks of it I thought that link was talking about both
C and C++


So if an identifier is declared and used as an lvalue, the compiler
knows that lvalues type because its the type which the the identifier
is declared with, and if its pointer conversion the compiler knows the
lvalues type from context (for example *(int*)0x0 will be an lvalue of
type "int"), so is it the expression itself that has a type or does
that expression evaluate so that the compiler knows its type (and
therefor size), like "this lvalue evaluated, the object it designated
starts at address ****** and the type of that object is"?

An object is, and I quote: "a region of data storage in the execution
environment, the contents of which can represent values" so its an
entire region of memory (usally), which is usally identified by a
memory address?

"If an lvalue appears as the RHS of an assignment, it's just
evaluated, yielding the value stored in the designated object." so
there is no conversion going on? it evaluates the lvalue and reads the
data of the object that lvalue identified?

"Precedence has nothing to do with it."
I thought it was order of evaluation, and I'm just wondering why one
lvalue (indirection) is different from an identifer as an lvalue in
terms of evaluation, but its probably off topic since its a C++ bot
and what I linked earlier about C++ lvalues seem different than C's

"knows what type is going to be used for that object"
 
S

Stephen Sprunk

Given:

int x = 42;
int *ptr;

the expressions ``x'' and` ``*ptr'' are both lvalues. ``x''
unconditionally designates an object. ``*ptr'' may or may not
designate an object, depending on the value currently stored in
ptr; this is where the potential for undefined behavior comes in.

"ptr" also unconditionally designates an object. (I'm sure you knew
that; I just point it out for completeness.)
I mentioned that the C standard doesn't use the traditional meanings
of the terms. I'll summarize my understanding of what those
traditional meanings are.
...
An rvalue is just an ordinary value of
some type. An lvalue is something that, rather than being a *value*
of some type, identifies an *object* of some type. The traditional
terminology unifies these two things (having a value vs. identifying
an object) into the single concept of "value", divided into "rvalue"
and "lvalue". The names of course come from the contexts in which
they appear, the right side vs. the left side of an assignment.

Note that some expressions, such as ``2 + 2'' cannot be evaluated for
their lvalues. (In C terms, ``2 + 2'' is not an lvalue.)

The authors of the C standard chose to drop the concept of "rvalue"
(other than a brief mention in a footnote which matches the
traditional meaning) and redefine "lvalue" as a kind of expression
rather than as the result of evaluating such an expression.

Is dropping the term "rvalue" why the C Standard's definition of
"lvalue" is so tortuous--and continues to get even more so with each
revision as they try to correct problems with the prior one?

Digesting what you have said, this is how I mentally process the terms:

.. A modifiable lvalue is any expression which _could_ have a meaningful
result if it appeared on the LHS of an assignment.
.. A non-modifiable lvalue is any expression which _would_ be a
modifiable lvalue if it weren't const.
.. An rvalue is any expression which isn't an lvalue.
.. If an lvalue occurs in a context which does not require an lvalue, it
is evaluated to produce an rvalue.

Granted, that definitely isn't how the C Standard uses or defines the
terms, but aside from that, is it accurate enough for someone other than
a compiler author? Or is there some subtle flaw in there that will bite
me someday?

S
 
K

Keith Thompson

Stephen Sprunk said:
Is dropping the term "rvalue" why the C Standard's definition of
"lvalue" is so tortuous--and continues to get even more so with each
revision as they try to correct problems with the prior one?

I don't think so. I think the problem is with "lvalue", not with
"rvalue". I find lvalues to be a more complicated concept anyway, for
either definition.
Digesting what you have said, this is how I mentally process the terms:

. A modifiable lvalue is any expression which _could_ have a meaningful
result if it appeared on the LHS of an assignment.
. A non-modifiable lvalue is any expression which _would_ be a
modifiable lvalue if it weren't const.
. An rvalue is any expression which isn't an lvalue.
. If an lvalue occurs in a context which does not require an lvalue, it
is evaluated to produce an rvalue.

Granted, that definitely isn't how the C Standard uses or defines the
terms, but aside from that, is it accurate enough for someone other than
a compiler author? Or is there some subtle flaw in there that will bite
me someday?

Your definition of "rvalue" directly contradicts the standard's
definition; an "rvalue" is not an expression, it's the result of
evaluating an expression.

I'd probably drop your third bullet and replace "rvalue" by "value" in
the fourth.
 
P

Phil Carmody

bartc said:
Nicklas Karlsson said:
Hello,

I am quite confused about this, so I split it in to subquestions, here
we go:

1. Is an lvalue the expression itself, or is it the result yielded by
evaluation of an expression? Take this for example: int i = 10; int *p
= &i; and then dereference: *p; is the expression "*p" the thing you
call an lvalue or is an lvalue the result yielded by evaluating that
lvalue-expression?

A rule of thumb might be: if you can apply the & operator to it
(address-of), then it can be an lvalue (with a few exceptions such as
function names)

But here:

int A,B;

A = B;

Both A,B could be lvalues, but only A is being used as one. (In assembly,
you will find little difference between how the two are treated:

mov [A], # assuming memory-to-memory allowed

(I'm done a bit of compiler work; I would handle the assignment above as
follows:

*(&A) = B;


So you'd not want your variables in registers? Why on earth not?

Phil
 
S

Stefan Ram

Nicklas Karlsson said:
1. Is an lvalue the expression itself, or is it the result yielded by

An lvalue is an expression.
2. Rvalues, is rvalues the result yielded by an rvalue-expression, or
is it the expression itself? If its the result yielded by evaluation
of an rvalue-expression is an rvalue a plain value?

An rvalue is the value of an expression (the value of the
expression except when it is the operand of the sizeof
operator, the unary & operator, the ++ operator, the --
operator, or the left operand of the . operator or an
assignment operator [possibly parenthesized]).
the example of *p, the lvalue will be of type "int", if an lvalue-
expression always yields an address when evaluated, C could keep track

An lvalue designates an object, it does not have to
have a pointer type.
 
S

Stefan Ram

An lvalue is an expression.

Having read parts of the discussion:

I'd put it in these words, if I was invited to write a
specification for the language C:

Every expression might designate an object and/or a
value. (For the definition of the object and the value,
see the chapter "expressions", where this is specified
for each type of expression.)

Every operator can require each of its operands to
designate an object and/or a value. (See the chapter
"expressions", where this is specified for each
operator.)

For example, the assignment operator »=« requires its
left operand to designate an object and its right
operand to designate a value. It then writes this value
into that object.
 
K

Keith Thompson

Having read parts of the discussion:

I'd put it in these words, if I was invited to write a
specification for the language C:

Every expression might designate an object and/or a
value. (For the definition of the object and the value,
see the chapter "expressions", where this is specified
for each type of expression.)

Every operator can require each of its operands to
designate an object and/or a value. (See the chapter
"expressions", where this is specified for each
operator.)

For example, the assignment operator »=« requires its
left operand to designate an object and its right
operand to designate a value. It then writes this value
into that object.

Clarification: All expressions designate values; only some expressions
designate objects.

And of course some expressions that are lvalues may not designate
objects depending on the values of certain subexpresions; ``*ptr''
designates an object if and only if ptr happens to contain a valid
non-null address.
 
L

lawrence.jones

Keith Thompson said:
What the standard probably should say is "if an lvalue does not
designate an object when it is evaluated *in a context that requires
an lvalue*, the behavior is undefined.

Isn't that addition redundant? I can't think of *any* context where an
lvalue that doesn't desginate an object can be safely evaluated.
 
L

lawrence.jones

Stephen Sprunk said:
. A non-modifiable lvalue is any expression which _would_ be a
modifiable lvalue if it weren't const.

An array is a non-modifiable lvalue but is not const (only the elements
can be const in C, not the array itself).
 
N

Nicklas Karlsson

Let me summarize what I make of this (hopefully its correct):

What is an lvalue?
An expression that designates (identifies) an object, when evaluated
the compiler knows what object is being designated and what type that
object has.

What is an rvalue?
The result of an expression that is not an lvalue appearing in LHS (an
lvalue, when evaluated, yields an rvalue if it appears on RHS, that
is, the value of the object being designated is being fetched, however
if its on LHS it does not evaluate to an rvalue but rather evaluates
so the compiler knows where to store an rvalue, that is, it identifies
an object and what type that object has).

What is an object?
A region of data storage, usally an object is a place in memory, so it
usally has a starting address, but it could also be stored in other
ways, for example in the CPU's register and therefor won't have an
ordinary address.

Silly question, the lvalue (expression) itself has no type right? But
when its evaluated the compiler finds out what type the object that
the lvalue identifies has?
 
K

Keith Thompson

Nicklas Karlsson said:
Let me summarize what I make of this (hopefully its correct):

What is an lvalue?
An expression that designates (identifies) an object, when evaluated
the compiler knows what object is being designated and what type that
object has.

Close. Evaluation happens at run time; the compiler doesn't
necessarily know which object is being designated. It does know
the type of the object -- or rather the type imposed by the lvalue.
This might not be the declared type of the object itself. In fact,
the object might not even have a declared type.

Some examples (I haven't taken the time to test these):

int x, y, *ptr;
switch (rand() % 3) {
case 0: ptr = NULL; break;
case 1: ptr = &x; break;
case 2: ptr = &y; break;
}
*ptr; /* an lvalue, but the compiler has no idea whether it
designates x, y, or no object at all */

void *vptr = malloc(sizeof(int));
assert(vptr != NULL);
/* We've just created an object, but it has no inherent type. */
*(int*)vptr; /* the type is imposed by the lvalue */
*(unsigned*)vptr; /* same object, different lvalue, different type */

What is an rvalue?
The result of an expression that is not an lvalue appearing in LHS (an
lvalue, when evaluated, yields an rvalue if it appears on RHS, that
is, the value of the object being designated is being fetched, however
if its on LHS it does not evaluate to an rvalue but rather evaluates
so the compiler knows where to store an rvalue, that is, it identifies
an object and what type that object has).

Too many words. An rvalue is the value of an expression, that's all.
It's also a term that the Standard doesn't use, and I see little point
in using it while discussing C. said:
What is an object?
A region of data storage, usally an object is a place in memory, so it
usally has a starting address, but it could also be stored in other
ways, for example in the CPU's register and therefor won't have an
ordinary address.

I'd say "address" rather than "starting address". In C, an address is
typed. It doesn't point to the beginning of an object, it points to
the object.
Silly question, the lvalue (expression) itself has no type right? But
when its evaluated the compiler finds out what type the object that
the lvalue identifies has?

No, an lvalue, like any expression, has a type.
 

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,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top