address of function's return value

B

Ben Bacarisse

Keith Thompson said:
No, '*p' is an lvalue, regardless of the value of p. ('p' is also an
lvalue, but that's beside the point). But using '*p' in a context
that requires an lvalue invokes undefined behavior.

The lvalue-ness of an expression cannot depend on the run-time value
of any object. There are contexts that require lvalues, and the
determination of whether something is an lvalue must be made at
compilation time, since the failure to provide an lvalue is a
constraint violation, requiring a compile-time diagnostic.

For example:

int *p;
/* ... */
*p = 42;

The assignment is legal (not a constraint violation) because '*p' is
an lvalue (specifically a modifiable lvalue) regardless of what the
value of 'p' happens to be. If '*p' does not designate an object when
the assignment is evaluated (e.g., if p == NULL), the behavior is
undefined.

I can't provide chapter and verse, because the standard gets this
wrong. (This isn't just a disgreement; the wording in the standard
leads to logical contradictions.)

The confusion is understandable. As you say, the compiler must be
able to determine if the left operand of an assignment is a modifiable
lvalue:

6.5.16
...
Constraints
An assignment operator shall have a modifiable lvalue as its left
operand.

but in 6.5.3.2, * is defined like this:

... 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. If the operand has type "pointer to type",
the result has type "type". If an invalid value has been assigned to
the pointer, the behavior of the unary * operator is undefined.)

In my opinion, it takes some linguistic hoop-jumping to read that to
mean that *p is also an lvalue when p does *not* point to an object
(when it is == NULL, for example). It could have been written:

... If the operand points to a function, the result is a function
designator; otherwise the result is an lvalue. If the pointer
points to an object, the resulting lvalue designates that object.
If the operand has type "pointer to type", the result has type
"type". If an invalid value has been assigned to the pointer, the
behavior of the unary * operator is undefined.)

but its was not.
The C90 standard got this wrong by implying that lvalue-ness can
depend on run-time values. The C99 standard corrected that problem,
but went too far in the other direction, saying that any expression of
object type is an lvalue.

I see the current definition of * as a remnant of the old run-time
dependent meaning.
 
P

Philip Potter

Richard said:
pete said:

Whoops - s/lvalue/modifiable lvalue/

This is one of the stupid consequences of a broken C def of "lvalue". The
whole point of lvalues is that they can be put on the left of an
assignment operator, whereas rvalues cannot (except in an expression which
has an lvalue as its result). By making lvalue's definition overly broad,
they have rendered the term less useful and intuitive.

So it's not your fault you made that mistake, it's the committee's?

<g,d&r>
 
R

Richard Heathfield

Philip Potter said:
So it's not your fault you made that mistake, it's the committee's?

Yeah, they shoulda arsked me first, and I'da told 'em!

(Admittedly, when they made their mistake, I'd never even *heard* of C. But
they still should have arsked me first.)

You can run, but you can't hide!
 
R

Richard Tobin

You don't need to use the word "memory" to convey that concept, though.
[/QUOTE]
Right, the word "object" works better (and the standard's definition
of "object" uses the term "data storage", not "memory").

That depends who you're explaining it to. If they are familiar with
the C standard's definition of object it may work better, but in that
case they probably already know what an lvalue is.
Sure you can. An expression that designates to an object in read-only
memory can be an lvalue; it just can't be a modifiable lvalue.

Which (surprisingly) matches the description of an lvalue as a location
in memory; and a modifiable lvalue is a modifiable location in memory.

-- Richard
 
A

Army1987

No. p is the lvalue, now NULL. Expressing *p while (p == NULL) is a no
no. If p eventually holds the address of an int object in memory, then
*p will be an lvalue.

*p is a lvalue. You can do sizeof *p, or &*p. And accessing it is
UB, but not a constraint violation <ot>(and by doing some system-
-specific magic it could behave like a normal int object)</ot>.
 
A

Army1987

Richard Tobin said:
jacob navia said:
lvalues refer to locations in memory.
Nope

register int m=7;
[...]
And if you really want pedantry, registers are a kind of memory.

True, but if you're going to get into which "kind of memory", you need to
be more specific. Clearly, you can't use "lvalue" to refer to locations in
read-only memory, for example.

I think that
const int a = 42;
is a lvalue...

(BTW, depending on what "kind of memory" is, even a numeric
constant such as 234 has to be "remembrerd" in some way, but it is
not a lvalue, unless you interpret C99 literally.)
 
K

Keith Thompson

Army1987 said:
I think that
const int a = 42;
is a lvalue...
[...]

No, but there's an lvalue lurking nearby.

'const int a = 42;' is a declaration; an lvalue is a kind of expression.

Given the declaration, the expression 'a' is an lvalue. (As usual,
I'm using single quotes to delimit snippets of C code; I'm not
referring to a character constant.)
 
P

pete

Keith said:
Army1987 said:
I think that
const int a = 42;
is a lvalue...
[...]

No, but there's an lvalue lurking nearby.

'const int a = 42;' is a declaration;
an lvalue is a kind of expression.

Given the declaration, the expression 'a' is an lvalue. (As usual,
I'm using single quotes to delimit snippets of C code; I'm not
referring to a character constant.)

I use parentheses when I'm quoting C expressions.

Given the declaration, (a) is an lvalue.
 
K

Keith Thompson

pete said:
Army1987 said:
I think that
const int a = 42;
is a lvalue...
[...]

No, but there's an lvalue lurking nearby.

'const int a = 42;' is a declaration;
an lvalue is a kind of expression.

Given the declaration, the expression 'a' is an lvalue. (As usual,
I'm using single quotes to delimit snippets of C code; I'm not
referring to a character constant.)

I use parentheses when I'm quoting C expressions.

Given the declaration, (a) is an lvalue.

Not a horrible idea, but I think I'll stick with single quotes. (I
used to use double quotes, but of course "42" or "x + y" is a valid
string literal.) An expression in parentheses is a different
expression; it's identical for most purposes, but there are some
subtle differences. And not every code snippet I quote is an
expression; consider 'return 42;'.

It's safe to assume that if I write '42', it's not a multicharacter
character constant unless I say so.

I suppose I could use dollar signs: ($a$ is an lvalue), but that's
ugly.

It would be nice if there were a clc convention for quoting short
in-line code snippets unambiguously, but I can't think of a really
good one. But if something is ambiguous, I can always put it on a
line by itself:
'a'
is a character constant, and so is
'ab'
..
 
A

Army1987

Army1987 said:
I think that
const int a = 42;
is a lvalue...
[...]

No, but there's an lvalue lurking nearby.

'const int a = 42;' is a declaration; an lvalue is a kind of expression.

Given the declaration, the expression 'a' is an lvalue.
I meant that...
 
A

Army1987

On Thu, 27 Sep 2007 17:28:54 -0700, Keith Thompson wrote:

[How to quote code snippets? Both "" and '' are potentially
ambiguous]
I suppose I could use dollar signs: ($a$ is an lvalue), but that's
ugly.
Good idea to pick an ASCII printable character not in the basic
character set. But there is one of them which is much less ugly.
(That's how expressions are quoted on a failed assert() on my
system. Well, only the left quote is that character, the right one
is an apostrophe. But nothing forbids us to use it as a right
quote, too, even if it isn't as much pretty; but it's still less
ugly than $.)
Given the declaration `const int a = 42;`, `a` is a lvalue.
 
K

Keith Thompson

Army1987 said:
On Thu, 27 Sep 2007 17:28:54 -0700, Keith Thompson wrote:

[How to quote code snippets? Both "" and '' are potentially
ambiguous]
I suppose I could use dollar signs: ($a$ is an lvalue), but that's
ugly.
Good idea to pick an ASCII printable character not in the basic
character set. But there is one of them which is much less ugly.
(That's how expressions are quoted on a failed assert() on my
system. Well, only the left quote is that character, the right one
is an apostrophe. But nothing forbids us to use it as a right
quote, too, even if it isn't as much pretty; but it's still less
ugly than $.)
Given the declaration `const int a = 42;`, `a` is a lvalue.

Not bad, but I think it's still visually ambiguous; in some fonts (and
with some aging eyes) the ' and ` characters can be difficult to
distinguish.

But how about this?

Given the declaration ``const int a = 42;'', ``a'' is an lvalue.

It looks a little silly in the font I'm currently using (the ` is
slanted but the ' isn't), but it's unambiguous and I've seen it in
other documentation.

I think we've got something here.
 
A

Army1987

On Wed, 26 Sep 2007 19:37:09 -0700, Keith Thompson wrote:

[About wheter *(int *)NULL is a lvalue]
I can't provide chapter and verse, because the standard gets this
wrong. (This isn't just a disgreement; the wording in the standard
leads to logical contradictions.)

The C90 standard got this wrong by implying that lvalue-ness can
depend on run-time values. The C99 standard corrected that problem,
but went too far in the other direction, saying that any expression of
object type is an lvalue.
What a mess... The funniest thing is that in eight years since
C99 to TC3 (n1256) nobody noticed that. Of course 6.3.2.1 isn't
intended to mean that 42 is a lvalue, and since it doesn't
designate an object the behavior is undefined when it is
evaluated.

Maybe a definition such "A lvalue is an identifier designing an
object, a string literal, or the result of operators [ ], ->, .
and unary *, provided that they don't violate any constraint, and,
in the case of ., that the left operand is a lvalue." would do
that, wouldn't it? (Maybe compound literals, too?)
 
K

Keith Thompson

Army1987 said:
On Wed, 26 Sep 2007 19:37:09 -0700, Keith Thompson wrote:
[About wheter *(int *)NULL is a lvalue]
I can't provide chapter and verse, because the standard gets this
wrong. (This isn't just a disgreement; the wording in the standard
leads to logical contradictions.)

The C90 standard got this wrong by implying that lvalue-ness can
depend on run-time values. The C99 standard corrected that problem,
but went too far in the other direction, saying that any expression of
object type is an lvalue.
What a mess... The funniest thing is that in eight years since
C99 to TC3 (n1256) nobody noticed that. Of course 6.3.2.1 isn't
intended to mean that 42 is a lvalue, and since it doesn't
designate an object the behavior is undefined when it is
evaluated.

Well, I noticed it before TC3 came out (though I'm having trouble
finding the thread on comp.std.c; I *thought* the subject was
something like "Is 42 an lvalue", but Google can't find it).
Maybe a definition such "A lvalue is an identifier designing an
object, a string literal, or the result of operators [ ], ->, .
and unary *, provided that they don't violate any constraint, and,
in the case of ., that the left operand is a lvalue." would do
that, wouldn't it? (Maybe compound literals, too?)

I think the C90 definition, that

An _lvalue_ is an expression (with an object type or an incomplete
type other than void) that designates an object.

was *almost* correct. It just needed some added wording to say that
an expression can be an lvalue even if it doesn't happen to designate
an object when it's evaluated, as long as it *could* do so.

I suggest:

An _lvalue_ is an expression (with an object type or an incomplete
type other than void) that designates an object, or that could
designate an object.

with a footnote saying that the last clause covers cases like
``int *ptr = NULL;'', where ``*ptr'' is an lvalue even though
it doesn't currently designate an object.

The "could designate" wording isn't precise enough for my taste, but I
haven't seen a better proposal. It's certainly better than having a
definition that's just wrong.
 
P

pete

Keith said:
Army1987 said:
On Wed, 26 Sep 2007 19:37:09 -0700, Keith Thompson wrote:
[About wheter *(int *)NULL is a lvalue]
I can't provide chapter and verse, because the standard gets this
wrong. (This isn't just a disgreement; the wording in the standard
leads to logical contradictions.)

The C90 standard got this wrong by implying that lvalue-ness can
depend on run-time values.
The C99 standard corrected that problem,
but went too far in the other direction,
saying that any expression of object type is an lvalue.
What a mess... The funniest thing is that in eight years since
C99 to TC3 (n1256) nobody noticed that. Of course 6.3.2.1 isn't
intended to mean that 42 is a lvalue, and since it doesn't
designate an object the behavior is undefined when it is
evaluated.

Well, I noticed it before TC3 came out (though I'm having trouble
finding the thread on comp.std.c; I *thought* the subject was
something like "Is 42 an lvalue", but Google can't find it).

http://groups.google.com/group/comp.lang.c/msg/e6f7d20cb0e685bb

Back in 2002, we used to use 5 instead of 42
as the example for this particular topic.
Pai-Yi HSIAO was the first to bring it to my attention.
I argued and lost.

My impression is that the C standard committee is not
strongly motivated to fix any part of the standard
that isn't actually causing a problem for a C implementor.
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top