late night confusion with -> and .

A

Ark Khasin

I heard a few times, and may have repeated thoughtlessly, that p->m is
in a way a shorthand for (*p).m
The standard doesn't seem to have a notion of this; this also sounds
downright wrong if p is a pointer to a volatile type.
How common is this misconception?
 
B

Ben Pfaff

Ark Khasin said:
I heard a few times, and may have repeated thoughtlessly, that p->m is
in a way a shorthand for (*p).m
The standard doesn't seem to have a notion of this; this also sounds
downright wrong if p is a pointer to a volatile type.
How common is this misconception?

I certainly have this misconception.

I don't immediately see the distinction you're making. Can you
explain further?
 
A

Ark Khasin

Ben said:
I certainly have this misconception.

I don't immediately see the distinction you're making. Can you
explain further?
volatile T *p;
(*p) - as in (*p).m - requires actually reading *p, which in turn may
affect the content of *p. p->m only affects the member m.
 
A

Ark Khasin

Ark said:
volatile T *p;
(*p) - as in (*p).m - requires actually reading *p, which in turn may
affect the content of *p. p->m only affects the member m.
And now I am confused even more.
volatile struct T s;
"Natural" s.m requires evaluation (read) of s, doesn't it?
Should I write (&s)->m so as to leave other members unaffected?
 
P

Peter Nilsson

Ark Khasin said:
I heard a few times, and may have repeated thoughtlessly,
that p->m is in a way a shorthand for (*p).m

They are potentially distinct in C++ since one can overload
operators. But that does not apply in C.
The standard doesn't seem to have a notion of this;

The definitions of these operators seem to, at face value,
imply that relationship. There's even a non-normative
footnote that says (&E)->m is E->m if &E is valid.
this also sounds downright wrong if p is a pointer to a
volatile type.

What difference would that make?
How common is this misconception?

You've yet to demonstrate that it actually is a misconception.
 
B

Ben Pfaff

Ark Khasin said:
volatile T *p;
(*p) - as in (*p).m - requires actually reading *p, which in turn may
affect the content of *p. p->m only affects the member m.

Hmm. The unary * operator yields an lvalue that designates an
object. I suspect that does not necessarily mean that the
contents of the lvalue is read, even by the abstract machine.
But I do not have a citation to offer that confirms that
suspicion. I hope that someone more authoritative has a better
suggestion.
 
A

Ark Khasin

Peter said:
They are potentially distinct in C++ since one can overload
operators. But that does not apply in C.


The definitions of these operators seem to, at face value,
imply that relationship. There's even a non-normative
footnote that says (&E)->m is E->m if &E is valid.


What difference would that make?


You've yet to demonstrate that it actually is a misconception.
Indeed, thank you for pointing out the Footnote 79) If &E is a valid
pointer expression (where & is the ‘‘address-of ’’ operator, which
generates a pointer to its operand), the expression (&E)->MOS is the
same as E.MOS.
I honestly don't know how to read it: an expression has a value and side
effects. No-one argues with the values part. It's the side effects that
bother me...
 
A

Ark Khasin

Ben said:
Hmm. The unary * operator yields an lvalue that designates an
object. I suspect that does not necessarily mean that the
contents of the lvalue is read, even by the abstract machine.
But I do not have a citation to offer that confirms that
suspicion. I hope that someone more authoritative has a better
suggestion.
My naive thinking is that if
volatile unsigned char *uart_receive;
*uart_receive; //discard the character, clear the interrupt source
is a valid practice, then unary * does evaluate (read) the value.
Similarly,
volatile uart_t *uart;
uart->receive; //discard the character, clear the interrupt source
But then
(*uart).receive;
seems to do a lot more of unwanted stuff.
 
U

user923005

I heard a few times, and may have repeated thoughtlessly, that p->m is
in a way a shorthand for (*p).m
The standard doesn't seem to have a notion of this; this also sounds
downright wrong if p is a pointer to a volatile type.

If you have an object, and you want to change a member, then it is:
p.m = foo;

If you have a pointer to an object, and you want to change a member,
then it is either:
p->m = foo;
Or:
(*p).m = foo;

Nobody uses the second form. Everyone uses the first form. I don't
know why it came out that way, but if you write (*p).m you will get
raised eyebrows, even though they are totally equivalent expressions.

How common is this misconception?

Really, really rare.
 
C

christian.bau

My naive thinking is that if
    volatile unsigned char *uart_receive;
    *uart_receive; //discard the character, clear the interrupt source
is a valid practice, then unary * does evaluate (read) the value.

Severe warning here: This is one of the few places with a very severe
and very non-obvious between C and C++. Don't do this if you ever want
to reuse the same code in a C++ program (or you expect that someone
else _might_ want to do this in ten years time).

In one language, an lvalue-to-rvalue conversion takes place, which
accesses *uart_receive. In the other language, no such conversion
takes place, and there is no access. Better write "unsigned char dummy
= *uart_receive; ". (And I don't know which language does the access
and which one doesn't, the distinction is sufficiently obscure that
writing *uart_receive alone is a bug in each language).
 
B

Bart C

volatile T *p;
(*p) - as in (*p).m - requires actually reading *p, which in turn may
affect the content of *p. p->m only affects the member m.

*p by itself may well involve reading *p, but it is followed by .m and is
also an lvalue and you may find that the internal workings of the compiler
will insert an implicit & in there which will cancel the *.

Similarly, when writing:

a=b

It clearly does not fetch the value of a. The compiler may (I'm guessing)
treat it as:

*(&a) = b

so no loading of a's value occurs, only it's address.

Bart
 
J

Jack Klein

Severe warning here: This is one of the few places with a very severe
and very non-obvious between C and C++. Don't do this if you ever want
to reuse the same code in a C++ program (or you expect that someone
else _might_ want to do this in ten years time).

In one language, an lvalue-to-rvalue conversion takes place, which
accesses *uart_receive. In the other language, no such conversion
takes place, and there is no access. Better write "unsigned char dummy
= *uart_receive; ". (And I don't know which language does the access
and which one doesn't, the distinction is sufficiently obscure that
writing *uart_receive alone is a bug in each language).

You are just plain wrong about this. In both languages the lvalue to
rvalue conversion is performed.

Perhaps you are confused with the way the way the value yielded by the
assignment operator can break volatile objects in C++.

Given:

/* receive and transmit registers share the same address,
as in the ubitquious 16c550 family
*/
volatile unsigned char *uart_rx_tx = /* ... */;

....then:

void uart_xmit(int uch)
{
if ('\r' == (*uart_rx_tx = uch))
{
*uart_rx_tx = '\n';
}
}

The if evaluation requires the value of the assignment operator.

In C, the value of the assignment operator is an rvalue, not an
lvalue. It is the value assigned, that is the rvalue that is actually
written to the destination. It is the value of the right hand side
after conversion, if necessary, to the type of the right hand side. So
it is the value of the int "uch" after truncation to unsigned char.

In C++, on the other hand, the assignment operators yield lvalues, in
this case the object pointed to by "uart_rx_tx". Since the value is
used in the if expression, lvalue to rvalue conversion must be
performed. Since the object is volatile, the conversion must be
performed by reading the value of the object.

So a conforming C++ compiler must first convert the int "uch" to an
unsigned char, write that unsigned char via the pointer, then read
back the value via the pointer to yield the value of the assignment.
In the process, it will not read the value just written to the UART's
transmit register, but will instead read a received character from the
UART's received register.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
B

Ben Pfaff

Jack Klein said:
You are just plain wrong about this. In both languages the lvalue to
rvalue conversion is performed.

C does not have a conversion called an lvalue-to-rvalue
conversion. C++ does (ISO 14882:1998 clause 4.2
"Lvalue-to-rvalue conversion"). This is probably the distinction
that Christian is making.
 
H

Harald van Dijk

C does not have a conversion called an lvalue-to-rvalue conversion.

Technically true, but C does have an lvalue-to-value conversion, which
might as well be called an lvalue-to-rvalue conversion.

6.3.2.1p2:
"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, an lvalue that does not have array
type is converted to the value stored in the designated object (and is
no longer an lvalue). [...]"
C++ does (ISO 14882:1998 clause 4.2
"Lvalue-to-rvalue conversion"). This is probably the distinction
that Christian is making.

Considering C is the language in which the lvalue-to-rvalue conversion
takes place, no, probably not. <OT>In C++, an lvalue expression
statement, even of qualified type, is not converted to an rvalue, because
the lvalue-to-rvalue conversion cannot generally be optimised away even
if the rvalue is immediately discarded.</OT>
 

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
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top