?: as an lvalue

P

Philip Potter

Willem said:
Philip wrote:
) That's exactly the point I was making too. I was saying that a.b is
) conditionally an lvalue based on a, so why not have a?b:c conditionally
) an lvalue based on b and c?

Correct me if I'm wrong, but isn't a.b *always* an lvalue in C ?

You are wrong according to n1256 6.5.2.3p3:

A postfix expression followed by the . operator and an identifier
designates a member of a structure or union object. The value is that of
the named member, and is an lvalue if the first expression is an
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lvalue. If the first expression has qualified type, the result has the
^^^^^^^
so-qualified version of the type of the designated member.



An example of where this matters:

struct a { int b; } inst_a;

struct a f(void) { inst_a.b = 0; return inst_a; }

int main(void) {
f().b = 10; /* error - f().b is not an lvalue */
return f().b; /* okay - f().b is an rvalue */
}
 
B

Ben Bacarisse

Philip Potter said:
Willem wrote:

You are wrong according to n1256 6.5.2.3p3:
struct a { int b; } inst_a;
struct a f(void) { inst_a.b = 0; return inst_a; }
int main(void) {
f().b = 10; /* error - f().b is not an lvalue */
return f().b; /* okay - f().b is an rvalue */
}

I like your example better than mine.
 
P

Philip Potter

Ben said:
That is not very helpful. If I asked "is 1+2 always an int" would
you reply "no in, float x = 1+2; it is a float"? lvalues often get their
contents taken in order to be turned into rvalues, but that is not
what Willem is asking.

To Willem: no. Section 6.5.2.3 "Structure and union members" para. 3
says of the . operator: "The value is that of the named member, and is
an lvalue if the first expression is an lvalue." This last part has
change bars so it is a recent addition to the text.

I didn't notice the change bar. What exactly do the change bars mean? Is
it everything which has changed since C99, or n1124, or what?

Philip
 
B

Ben Bacarisse

Philip Potter said:
Ben Bacarisse wrote:

I didn't notice the change bar. What exactly do the change bars mean?
Is it everything which has changed since C99, or n1124, or what?

My understanding is that they mark all changes between the current
draft and the published standard. The major elements added to the
draft are the three Technical Corrigenda. However, IANALL.
 
R

Richard

Ben Bacarisse said:
That is not very helpful. If I asked "is 1+2 always an int" would

I can see that my little bit humour based on usual c.l.c pedantry was
lost. I even added the ":-;" to make it clear. Oh well. Sorry.
 
B

Ben Bacarisse

Richard said:
I can see that my little bit humour based on usual c.l.c pedantry was
lost. I even added the ":-;" to make it clear. Oh well. Sorry.

Would it be too pedantic to say that :-; is hardly a well recognised
emoticon. My news readers renders most, but that one is just too
bizarre. I thought it was just a typo for your punctuation
introducing an example. The lamer the joke, the more important the
smiley that flags it...
 
R

Richard

Ben Bacarisse said:
Would it be too pedantic to say that :-; is hardly a well recognised

Then you live on another planet? (obligatory ":)"). Was it you who
also claimed he did not recognise the word "nOOb"? Not that I dont
believe you - I just find it VERY hard to believe that, hate them as
some do, you are not aware of such commonly used shortcuts.
emoticon. My news readers renders most, but that one is just too
bizarre. I thought it was just a typo for your punctuation
introducing an example. The lamer the joke, the more important the
smiley that flags it...

It is one of the most common used "smileys". It is a winking smile.

I said humour. But it was also correct.

True to the true c.l.c anal retentive language laws, "a.b" is not
"always" an lvalue.
 
B

Ben Bacarisse

Richard said:
Then you live on another planet? (obligatory ":)"). Was it you who
also claimed he did not recognise the word "nOOb"? Not that I dont
believe you - I just find it VERY hard to believe that, hate them as
some do, you are not aware of such commonly used shortcuts.

You do love to invent your corespondents' views don't you?
It is one of the most common used "smileys". It is a winking smile.

You still don't see the mistake you've made? I think a ;-) is called for!
 
L

lawrence.jones

Andrey Tarasevich said:
What it illustrates is that the type-compatibility requirements are
_already_ in the language. They are already there and there's no way
around them. The fact that '?:' returns a non-lvalue in C doesn't really
make things easier. And making '?:' return an lvalue wouldn't really
make things harder.

But there's no general requirement that the second and third argument
have compatible type; the requirement is indirect and only applies in
certain contexts. For example:

int i = 0;
double d = 1.0;

1 < 0 ? d : i;

is perfectly valid even though d and i do not have compatible type.

And I don't think compatible types is sufficiently strong, I think they
would have to be identical (which is what C++ requires, I believe).

-Larry Jones

I like maxims that don't encourage behavior modification. -- Calvin
 
L

lawrence.jones

Ben Bacarisse said:
I suspect it is more likely to have been a case of there being no
strong reason to alter existing practice, rather than there being some
killer technical reason why it is too hard or does not fit with C's
view of the world.

Exactly. I'd be curious to know what it was that persuaded C++ to alter
existing practice.

-Larry Jones

I told her to expect you to deny everything. -- Calvin
 
L

lawrence.jones

Philip Potter said:
I didn't notice the change bar. What exactly do the change bars mean? Is
it everything which has changed since C99, or n1124, or what?

Everything since C99.

-Larry Jones

Summer vacation started! I can't be sick! -- Calvin
 
H

Harald van Dijk

But there's no general requirement that the second and third argument
have compatible type; the requirement is indirect and only applies in
certain contexts. For example:

int i = 0;
double d = 1.0;

1 < 0 ? d : i;

is perfectly valid even though d and i do not have compatible type.

And I don't think compatible types is sufficiently strong, I think they
would have to be identical (which is what C++ requires, I believe).

void (*fp1)();
void (*fp2)(void);
void g(void) {
(rand() ? fp1 : fp2) = g;
}
void h(void) {
extern void (*fp1)(void);
(rand() ? fp1 : fp2) = g;
}

Okay, in C++, fp1 and fp2 are identical types, but if C were extended to
allow use of ?:'s result as an lvalue, it looks a bit silly to allow h
but not g.

Allowing ?: to be used as an lvalue could break code, by the way:
currently,

volatile int i;
volatile int j;
rand() ? i : j;

causes a read of both i and j, while this would change to read only one
of them.
 
K

Keith Thompson

Andrey Tarasevich said:
Richard said:
Exactly why a?b:c can't appear like that on the left-hand-side of
an assignment is a bit of a mystery; after all a, a.b, a->b, a
and so on can all appear on the lhs without the programmer having
to insert explicit address-of operators.
Because b and c are two distinct objects that can have different types,
which makes the type of any resulting lvalue somewhat problematic.

That should nail it ...


No, that completely misses it. For example, what will happen if you
try to compile this

double* d;
int* i;

1 < 0 ? d : i;

Here's another example

struct A { int i; } a;
struct B { int i; } b;

1 < 0 ? a : b;

I'll answer it for you: in both cases the code is invalid. It won't
compile. Why? Because the existing type-compatibility requirements
imposed on the second and third parameter of '?:' have been
violated. Note, that this is normal C '?:', which returns a
non-lvalue. Did that little "non-lvalue" detail somehow help it to
compile in the above example? No, it didn't.

What it illustrates is that the type-compatibility requirements are
_already_ in the language. They are already there and there's no way
around them. The fact that '?:' returns a non-lvalue in C doesn't
really make things easier. And making '?:' return an lvalue wouldn't
really make things harder.

(And, once again, this is a purely academic argument for me. I'm not
trying to campaign for lvalue-returning '?:')


But the existing rules for the second and third operands of ?: are
relatively loose, too loose to allow for an easy definition of the
semantics of a hypothetical lvalue-yielding ?: operator. For example,
they can be of two different arithmetic types. This is perfectly
legal:

int x;
double y;
1 ? x : y;

and the "usual arithmetic conversions" are applied. Note that these
conversions are not applied to lvalues, and it's difficult to imagine
how they could be in a consistent manner:

(1 ? x : y) = 42;

Not immpossible, just difficult, and IMHO not worth the effort.

*If* I wanted to advocate allowing ?: as an lvalue, I'd probably want
to require the second and third arguments to be of *the same* type (or
at least of compatible types) if it's used in a context that requires
an lvalue, making the above a constraint violation but allowing:

int x, y;
(1 ? x : y) = 42;

For a non-lvalue context, I'd leave the rules as they are.

(Or I'd look at how C++ defines it.)
 
B

Ben Bacarisse

Exactly. I'd be curious to know what it was that persuaded C++ to alter
existing practice.

<now off-topic>
I am no expert, but C++ does this a lot. For example, functions are
lvalues as are the results of assignment operators (including ++ and
--) and the comma operator. I think it fits in well with references;
producing fewer special cases and surprises.
 
S

santosh

Richard said:
Then you live on another planet? (obligatory ":)"). Was it you who
also claimed he did not recognise the word "nOOb"? Not that I dont
believe you - I just find it VERY hard to believe that, hate them as
some do, you are not aware of such commonly used shortcuts.


It is one of the most common used "smileys". It is a winking smile.

Shouldn't a winking smile be ;-) ?
 
A

Andrey Tarasevich

Willem said:
Philip wrote:
) That's exactly the point I was making too. I was saying that a.b is
) conditionally an lvalue based on a, so why not have a?b:c conditionally
) an lvalue based on b and c?

Correct me if I'm wrong, but isn't a.b *always* an lvalue in C ?

No. It is only lvalue when 'a' itself is an lvalue.
 
A

Andrey Tarasevich

Richard said:
No. Not always :-;

e.g

c = a.b;

Here it is an rvalue ....

Wrong. If 'a' is an lvalue, then 'a.b' is an lvalue as well, even if it
is used on the rhs of an assignment.

What really happens here is that the _lvalue_ 'a.b' will get converted
to an rvalue stored in 'a.b' (say, 42), and then that rvalue will be
"passed" to the assignment operator, which will store it into 'c'.
 
F

Flash Gordon

Philip Potter wrote, On 01/04/08 13:15:
Bartc said:
Philip Potter said:
Flash Gordon wrote:
Bartc wrote, On 31/03/08 18:45:
[discussion of ?: as an lvalue compared to other lvalue expressions]
a: You can write a = x without writing *(&a) = x
You can't do 3 = x

a.b: You can write a.b = x without writing *(&a + offsetof b) = x
You can't do 5.b or a.5
But you can do f().b
E1.E2 is only an lvalue if E1 is an lvalue.

Well f().b = x would be an error too. I was pointing out that where
a.b=x is legal, you can write it without all this *(&a+offsetof
business, because compiler magic is being applied.

That's exactly the point I was making too. I was saying that a.b is
conditionally an lvalue based on a,

Well, since that is a post C99 change to the language I'm sure you can
forgive some people for forgetting it.

Also, remember that the original decision was made before C89 was
published (either in the standardisation process or earlier) so the fact
that the . operator now conditionally produces an lvalue would not have
impinged on anyone's thought processes back then.

I suspect with C99 no one even thought about it rather than the
committee thinking about it and rejecting the idea.
so why not have a?b:c conditionally
an lvalue based on b and c?

<snip>

I agree it could be done. I also don't have any objection to the
standard being changed to allow it.
 
P

Philip Potter

Flash said:
Philip Potter wrote, On 01/04/08 13:15:
Bartc said:
Flash Gordon wrote:
Bartc wrote, On 31/03/08 18:45:
[discussion of ?: as an lvalue compared to other lvalue expressions]
a: You can write a = x without writing *(&a) = x
You can't do 3 = x

a.b: You can write a.b = x without writing *(&a + offsetof b) = x
You can't do 5.b or a.5
But you can do f().b
E1.E2 is only an lvalue if E1 is an lvalue.
Well f().b = x would be an error too. I was pointing out that where
a.b=x is legal, you can write it without all this *(&a+offsetof
business, because compiler magic is being applied.
That's exactly the point I was making too. I was saying that a.b is
conditionally an lvalue based on a,

Well, since that is a post C99 change to the language I'm sure you can
forgive some people for forgetting it.

Yes; I hadn't noticed the change bars. Having said that, the change bar
is only on the second line of the paragraph:

1 A postfix expression followed by the . operator and an identifier
designates a member of
2 a structure or union object. The value is that of the named member,82)
and is an lvalue if
3 the first expression is an lvalue. If the first expression has
qualified type, the result has
4 the so-qualified version of the type of the designated member.

(I have numbered the lines for clarity). I wonder what the original
wording was, because most of the relevant phrase (on line 3) is not marked.
 
H

Harald van Dijk

Yes; I hadn't noticed the change bars. Having said that, the change bar
is only on the second line of the paragraph:

1 A postfix expression followed by the . operator and an identifier
designates a member of
2 a structure or union object. The value is that of the named member,82)
and is an lvalue if
3 the first expression is an lvalue. If the first expression has
qualified type, the result has
4 the so-qualified version of the type of the designated member.

(I have numbered the lines for clarity). I wonder what the original
wording was, because most of the relevant phrase (on line 3) is not
marked.

The change is that the footnote has been added. The actual text has not
changed, as far as I can see, except that it used to not include "82)".
 

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,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top