lvalues and rvalues

  • Thread starter Nicklas Karlsson
  • Start date
K

Keith Thompson

Tim Rentsch said:
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).

It says it "is converted to" such an expression, not (quite) that it
"becomes" such an expression. So does the unconverted expression
still exist, and is *it* an lvalue?

Darned if I know. But yes, you have a good point.
 
T

Tim Rentsch

SG said:
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 didn't understand that from your posting. I thought
you were talking only about the '&x[y]' case (or
similar ones).
I was probably as buffled as you are now when I got your
response where you accused me of "deliberately misunderstanding"
things. :)

When I wrote "please don't deliberately misunderstand me to
supply a 'correction'", it was meant only as a request regarding
future behavior, not as an accusation over past behavior.

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.

I haven't read the C++ standard in any detail but I will take
your word for it that it's different. The fact that there _is_ a
difference reinforces my view that it's important to distinguish
such expressions as not being lvalues in C.
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
Keith Thompson 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).

It says it "is converted to" such an expression, not (quite) that it
"becomes" such an expression.

Yes, I was being casual in my wording, which I thought was okay
since I'd referred to an earlier posting where I gave exact
wording.
So does the unconverted expression
still exist, and is *it* an lvalue?

In a sense I think it does, because it's also possible to
have expressions that have array type that are not lvalues
(meaning, even before conversion), and this can be relevant
in some contexts. (*Disclaimer: I think. The case I'm
thinking of is accessing an array member of an value
expression with a structure value, and I don't think too
much about the rules for such cases because doing anything
too exotic in those cases is IMO bordering on insanity.
YMMV.)
Darned if I know. But yes, you have a good point.

My main point is both that it's the language of the Standard and
it's how most people with C experience think of expressions with
array type. I wasn't meaning to argue anything controversial,
just point out a case that's not completely uncommon but is
sometimes easy to overlook. My comment to your earlier posting
certainly wasn't meant as a correction, nor did I think I was
telling you anything you didn't already know. I guess I should
have made that clearer.
 
U

Uno

Sorry, Keith, for spurring you into extra innings on this. If you look
above, you can see how I read an extra not into it.

I counted them, and there were 2, which in english might cancel each
other out. (Russian not so much.)

My eyes have had a hard year a concussion, dryness and allergies.

snip
 
J

J de Boyne Pollard

For what it's worth: Several authorities consider "whether or not"
In informal English, or in formal technical English?

The authorities that I've seen don't make a distinction
when talking about "whether or not".
In formal technical English, saying "whether or not"
clearly removes a possible ambiguity; [...]

What ambiguity?
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.

You've just apparently said the same thing twice
("has no uninitialized variables" "does not have
uninitialized variables") and cast the twain as
opposites. Did you make a typing error there?
 
S

Stephen Sprunk

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.

Well, I thought that defining "lvalue" would be more straightforward if
there were something to contrast it to, as opposed to it being a lone
partial subset of "value".
Your definition of "rvalue" directly contradicts the standard's
definition; an "rvalue" is not an expression, it's the result of
evaluating an expression.

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

See above.

S
 
S

Stephen Sprunk

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

Argh! Thanks for pointing out that case. It would never occur to me to
do that, but mainly because I already know it's not legal; one _could_
define the semantics of assignment to an array, but C does not.

S
 
S

Stephen Sprunk

Do such fat pointer implementations really exist, check a significant
proportion of the accesses, and compile real world code into something
that works?

There is/was a bounds-checking implementation of GCC which used fat
pointers, but last I checked it didn't work too well since it wasn't
binary-compatible with non-checked libraries...

Still, it's completely legal, and one day someone might figure out how
to make such a beast practical.
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.

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?

I suppose one might distinguish between passing "arr" and passing
"&arr[0]"; the former would inherit the bounds of the entire array
object, but the latter would get the bounds of the specified element.

S
 
S

Stephen Sprunk

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

After a bit of thinking, I took a stab at how such an implementation
_might_ work, but I'm not 100% sure that it'd be conforming. Keith's
responses (to the above) seems to indicate it would be, but I'm still
not convinced either way.

S
 
B

Ben Bacarisse

Stephen Sprunk said:
On 08 Apr 2010 02:42, Phil Carmody wrote:
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.

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?

I suppose one might distinguish between passing "arr" and passing
"&arr[0]"; the former would inherit the bounds of the entire array
object, but the latter would get the bounds of the specified element.

I don't see how it could be allowed to, at least in the simple case of
an array of some basic data type. If, say, 'arr' is an array of chars,
then calling strlen(arr) and strlen(&arr[0]) must behave in the same
way. In fact, &arr[0] is defined to be arr+0 by 6.5.3.2 p3 and the +0
can't change the (implied) bounds.

To answer Phil's question, I don't think fblag can be prevented from
accessing fp[1] if fp is really a pointer to anywhere but the very end
of an array. That does not invalidate the idea of using fat pointers,
it just means that they can't police every situation.
 
T

Tim Rentsch

Eric Sosman said:
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!

Did I? It sounded like you asking a question,
not making a point.
 
T

Tim Rentsch

Stephen Sprunk said:
After a bit of thinking, I took a stab at how such an implementation
_might_ work, but I'm not 100% sure that it'd be conforming. Keith's
responses (to the above) seems to indicate it would be, but I'm still
not convinced either way.

Certainly there could be a conforming implementation along those
lines, for example for 'T' being 'int'. Any invertible mapping can
be applied to the bits of a memory address to make up the actual
bits in a stored pointer. There are certain constraints related to
certain classes of pointer types (eg, pointers to structs all have
the same representation and alignment), but if we limit ourselves to
the "related" pointer types for a particular scalar type (eg, int *,
const int *, volatile int *, etc), all of those could use the
mapping "base address + sizeof (int)" for the actual stored value.
The key observation is that the mapping is invertible; flipping all
the bits would also work. The trick of adding the size of the
pointed-to type does not work for structs, because pointers to
structs have to have the same representation, and different structs
have different sizes (basically, there is a problem with any kind of
pointer type where what it's pointing at might be an incomplete
type). But pointer to 'int' doesn't have these problems.
 
T

Tim Rentsch

J de Boyne Pollard said:
The authorities that I've seen don't make a distinction
when talking about "whether or not".

Ahhh. This strengthens my belief that this rule makes more sense in
informal English than it does in formal technical English.

In formal technical English, saying "whether or not"
clearly removes a possible ambiguity; [...]

What ambiguity?

When "whether" is part of a statement of implication, the distinction
between a one-way implication and a two-way implication.

You've just apparently said the same thing twice
("has no uninitialized variables" "does not have
uninitialized variables") and cast the twain as
opposites. Did you make a typing error there?

Although I probably could have found better phrasing, I meant what I
said as I typed it, and it illustrates the kind of ambiguity I
referred to. Given a conservative algorithm for detection of
uninitialized variables, we can, for some programs, be sure that
those programs have no uninitialized variables. What we _cannot_ do
is to look at an arbitrary program and then either (a) state with
certainty that it has no uninitialized variables, or (b) state with
certainty that some variables are used without being given initial
values. In other words this is a one-way implication; _if_ we say
a program has no uninitialized variables, then we can be sure that
it has no such variables, but if we _don't_ say a program has no
uninitialized variables then can't be sure either that it does or
doesn't have uninitialized variables. The algorithm can't be smart
enough in all cases to say Yea or Nay with absolute certainty.

Getting back to the original issue, the algorithm tells us _whether_
there is no problem, but it doesn't tell us _whether or not_ there
is no problem, because if it doesn't say there is no problem, there
might be a problem or there might not be, but we can't be sure which.

Does that make more sense now?
 
E

Ersek, Laszlo

Although I probably could have found better phrasing, I meant what I
said as I typed it, and it illustrates the kind of ambiguity I referred
to. Given a conservative algorithm for detection of uninitialized
variables, we can, for some programs, be sure that those programs have
no uninitialized variables. What we _cannot_ do is to look at an
arbitrary program and then either (a) state with certainty that it has
no uninitialized variables, or (b) state with certainty that some
variables are used without being given initial values. In other words
this is a one-way implication; _if_ we say a program has no
uninitialized variables, then we can be sure that it has no such
variables, but if we _don't_ say a program has no uninitialized
variables then can't be sure either that it does or doesn't have
uninitialized variables. The algorithm can't be smart enough in all
cases to say Yea or Nay with absolute certainty.

Similarly, "testing can prove only the presence of bugs, not their
absence".

Cheers,
lacos
 
J

J de Boyne Pollard

For what it's worth: Several authorities consider "whether or not"
Ahhh.  This strengthens my belief that this rule makes more sense
in informal English than it does in formal technical English.

It should do exactly the reverse, since it shows that only you
are making this distinction, and the rest of the world is not.
Go and read what Prai Jei wrote in this thread about the
fundamental meaning of the word "whether".
In formal technical English, saying "whether or not"
clearly removes a possible ambiguity; [...]
What ambiguity?

When "whether" is part of a statement of implication,
the distinction between a one-way implication and a
two-way implication.

That's not an ambiguity with "whether".
Although I probably could have found better phrasing,
I meant what I said as I typed it, and it illustrates
the kind of ambiguity I referred to.  

No, it doesn't. Saying the same thing twice doesn't
create ambiguity. What it does illustrate is confusion
on the writer's part when xe then asserts that there's
opposition between the two statements of the same thing.
[... a lot of stuff unrelated to "whether" elided ...]

Getting back to the original issue, the algorithm tells
us _whether_ there is no problem, but it doesn't tell us
_whether or not_ there is no problem, because if it
doesn't say there is no problem, there might be a
problem or there might not be, but we can't be sure which.

Does that make more sense now?

No, because again you are asserting that two statements
of the same thing are somehow different. There is no
difference here between something determining "whether
there is no problem" and that same thing determining
"whether there is a problem or not". The same
determination is being made.

I suggest going and looking the word up, and going and
reading (say) Eric Partridge on the subject. "whether"
really does mean a choice between two. "Or not" as one
of those choices in an is/isn't dichotomy is redundant,
and only really useful for emphasis. And as Prai Jei
said, "whether or not X", for "whether X or not", is
really placing the "or" in the wrong place, possibly
by false analogy to the idiom "whether or no", which
means "in all cases" and where the "or" is actually
between the two "whether" choices and a third "no"
choice that is in opposition to both
-- i.e. (A OR B) OR !(A OR B).
 
T

Tim Rentsch

J de Boyne Pollard said:
It should do exactly the reverse, since it shows that only you
are making this distinction, and the rest of the world is not.

Yes, isn't it interesting how different people can draw
opposite conclusions from the same data.
Go and read what Prai Jei wrote in this thread about the
fundamental meaning of the word "whether".

Sorry, I don't have the proper tools to track that down.
But please feel free to summarize his (her?) comments.
In formal technical English, saying "whether or not"
clearly removes a possible ambiguity; [...]
What ambiguity?

When "whether" is part of a statement of implication,
the distinction between a one-way implication and a
two-way implication.

That's not an ambiguity with "whether".

I understand that's your view. Other people hold
different views.
No, it doesn't. Saying the same thing twice doesn't
create ambiguity. What it does illustrate is confusion
on the writer's part when xe then asserts that there's
opposition between the two statements of the same thing.

Again, I understand that's how you interpret the
writing. Other people interpret it differently.
[... a lot of stuff unrelated to "whether" elided ...]

Getting back to the original issue, the algorithm tells
us _whether_ there is no problem, but it doesn't tell us
_whether or not_ there is no problem, because if it
doesn't say there is no problem, there might be a
problem or there might not be, but we can't be sure which.

Does that make more sense now?

No, because again you are asserting that two statements
of the same thing are somehow different. There is no
difference here between something determining "whether
there is no problem" and that same thing determining
"whether there is a problem or not". The same
determination is being made.

At the risk of sounding like a broken record, I realize
that how other people read the two statements doesn't
always match how you read them.
I suggest going and looking the word up, and going and
reading (say) Eric Partridge on the subject. "whether"
really does mean a choice between two. "Or not" as one
of those choices in an is/isn't dichotomy is redundant,
and only really useful for emphasis. And as Prai Jei
said, "whether or not X", for "whether X or not", is
really placing the "or" in the wrong place, possibly
by false analogy to the idiom "whether or no", which
means "in all cases" and where the "or" is actually
between the two "whether" choices and a third "no"
choice that is in opposition to both
-- i.e. (A OR B) OR !(A OR B).

I may do that sometime. However, no matter who thinks
what about how people should interpret English, it
doesn't necessarily follow that that's how people do
interpret English.
 
N

Nicklas Karlsson

I've been trying to swallow this entire thread, but I'm still not sure
about everything, another problem I have is that I spent today trying
to find answers and pretty much forgot the key questions, but I think
this is close enough to what I was wondering:

"An lvalue is an expression which potentially designates an object." -
This is the definition I got the impression of being right, and the
definition I used in my head when writing this.

About evaluation of lvalue...
If evaluation is a runtime thing and the offset of the variable who's
address is being fetched is known, does the lvalue evaluate then?

Take this for example (which is probably containts no-op's):
"*&i"

Here the compiler most likley knows i's offset, so maybe its -8 and
the compiler knows the type is "int", so it knows to start reading the
objects value at the address-offset -8 and to read sizeof(int) bytes.
Then what is the evaluation? Its not a runtime thing here right? Is
the evaluation the code it gets compiled into? If an lvalue already
identifies an object, why evaluate it? If the compiler does not know
what object the lvalue identifies, why is it said to identify an
object? Because it *does* in C? That is, in case of indirection... you
give it an address (or address to be) and the lvalue identifies an
object with that address and a type?

I'm skipping ahead a bit, if an lvalue always evaluates then this is a
question I want to ask:

About the indirection operator...
Basically, depending on context, the indirection operation may
evaluate to one of two different things, acctually, it always have to
evaluate to identify an object, if used where an lvalue is required,
it stops there, the evaluation is done, however when appearing in a
context that does not require an lvalue, the object identified will
have its value fetched, this means the expression evaluates to an
rvalue.

Is that correct?
 
B

Barry Schwarz

I've been trying to swallow this entire thread, but I'm still not sure
about everything, another problem I have is that I spent today trying
to find answers and pretty much forgot the key questions, but I think
this is close enough to what I was wondering:

"An lvalue is an expression which potentially designates an object." -
This is the definition I got the impression of being right, and the
definition I used in my head when writing this.

About evaluation of lvalue...
If evaluation is a runtime thing and the offset of the variable who's
address is being fetched is known, does the lvalue evaluate then?

If the result of evaluating the expression is an lvalue, then the
expression must be evaluated or you don't have an lvalue. lvalues
themselves do not necessarily cause an evaluation. But if the value
of the object the lvalue designates is needed, then evaluating the
lvalue produces that value.

What offset are you referring to that you think makes a difference?
Take this for example (which is probably containts no-op's):
"*&i"

There is a special exception for the *& construct. Neither operation
is performed.
Here the compiler most likley knows i's offset, so maybe its -8 and
the compiler knows the type is "int", so it knows to start reading the
objects value at the address-offset -8 and to read sizeof(int) bytes.

Evaluation of this expression, even without the exception, need not
require accessing any of the bytes in i (such as when the expression
is on the left of the assignment operator or the operand of the sizeof
operator). On those occasions when the value of i is required, the
compiler does not access i but rather generates code so that when the
evaluation occurs during execution the bytes are accessed.
Then what is the evaluation? Its not a runtime thing here right? Is

While constant expressions may be evaluated during compile time (i =
5+1; need not have an add in the code resulting from this statement),
the compiler is under no obligation to do so. In the more general
case, evaluation is usually a "runtime thing."
the evaluation the code it gets compiled into? If an lvalue already

You want to try rephrasing that sentence into something that more
clearly conveys you concern.
identifies an object, why evaluate it? If the compiler does not know

Because the value of the object may not be known until execution.
what object the lvalue identifies, why is it said to identify an
object? Because it *does* in C? That is, in case of indirection... you

Why do you think they are called "variables"?
give it an address (or address to be) and the lvalue identifies an
object with that address and a type?

The compiler has no way of knowing what the actual address of an
object will be at execution time. What it does do is generate code
that will correctly compute the address when it is needed.
I'm skipping ahead a bit, if an lvalue always evaluates then this is a
question I want to ask:

About the indirection operator...
Basically, depending on context, the indirection operation may
evaluate to one of two different things, acctually, it always have to
evaluate to identify an object, if used where an lvalue is required,
it stops there, the evaluation is done, however when appearing in a
context that does not require an lvalue, the object identified will
have its value fetched, this means the expression evaluates to an
rvalue

Not always. x = sizeof (*y); will not fetch the value of y or the
value of the object y points to. In fact, the code is legal even if
the value of y or the value of *y is indeterminate.
Is that correct?

Unless you are writing a compiler, you are drilling way too deep.
 
K

Keith Thompson

Barry Schwarz said:
If the result of evaluating the expression is an lvalue, then the
expression must be evaluated or you don't have an lvalue. lvalues
themselves do not necessarily cause an evaluation. But if the value
of the object the lvalue designates is needed, then evaluating the
lvalue produces that value.

An lvalue is not the result of evaluating an expression; an lvalue *is*
an expression (at least as C defines the term).

Like any expression, an lvalue may or may not be evaluated, depending on
the context in which it appears.

[...]
 
N

Nicklas Karlsson

Oh, maybe "does not require an lvalue" was a bad statement, maybe
"does require an rvalue" would be more correct, I do think that the
sizeof operator takes the type of lvalues, and the type of rvalues, it
does not need the lvalue to evaluate to an rvalue, the lvalue doesn't
even need to designate valid object, it only needs to know the type
imposed by the lvalue.

I guess my beef is with the term "evaluation", I do not quite
understand it. To me, it seems as an lvalue in a context that requires
an lvalue will partly evaluate at compile time (if its a normal memory
based variable for example), that is, being compiled into code that
identifies an object, but its not fully evaluated, at runtime the
offset decided for this variable will be used to calculate the
address. But then we have register variables, I do not see any
possibility for it not to be fully evaluated at compile time, it knows
the register the lvalue uses, and it knows the type (therefore object
size, that is, part of the register used) of the lvalue. Here is where
I start going "is this really evaluation?" because I don't see that
any action is needed (no evaluation needed, if this isn't what you
call evaluation).

I'd be grateful is someone could tell me more about what evaluation
really means. MSDN says its:
* Computes a value
* Designates an object or function
* Generates side effects

....but does not say the nature of it, if the code generated could be
considered evaluation for example.
 

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,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top