[comp.unix.questions] why p->member ?

stanonik@nprdc.arpa (Ron Stanonik) (08/04/88)

While explaining pointers to structures someone asked why
the -> operator was needed; ie, why couldn't the members be
referenced as p.member.  My first response was, we're talking
about pointers to structures, not structures, so a separate
operator is needed.  On second thought though, since the
compiler knows whether the variable is a pointer or structure,
why shouldn't the compiler do the "right" thing when it sees
p.member?

Could this ever be ambiguous?  That is, is there some declaration
of p such that p could be interpreted as both a structure and
a pointer to a separate structure.  I tried fiddling around
with unions, but could not produce such an object.

Does it make a lot more work for the compiler?  It doesn't
seem so, since it's already keeping track of p's type.

Thanks,

Ron Stanonik
stanonik@nprdc.arpa

karish@denali.stanford.edu (Chuck Karish) (08/04/88)

In article <16734@adm.ARPA> stanonik@nprdc.arpa (Ron Stanonik) writes:
>While explaining pointers to structures someone asked why
>the -> operator was needed; ie, why couldn't the members be
>referenced as p.member.

This is explained in p. 122 of K&R, first edition.
Briefly, if we define a structure pointer with

	struct date { int year, month, day } *pd;

then

	pd->year

is equivalent to

	(*pd).year.

The parentheses show that we're dereferencing pd, not year.
Interpretation of the sort you discuss, in which the compiler
figures out automatically that p is a pointer and decides
on its own to dereference it, would be pretty confusing, not
to mention inconsistent with the way other pointers are handled.
Anyway, it's not part of the language.

Chuck Karish	ARPA:	karish@denali.stanford.edu
		BITNET:	karish%denali@forsythe.stanford.edu
		UUCP:	{decvax,hplabs!hpda}!mindcrf!karish
		USPS:	1825 California St. #5   Mountain View, CA 94041

ash@a.cs.okstate.edu (Ashok Rathi) (08/06/88)

"p.member" will be interpreted as "p" being the name of the structure and
"member" being the element of that structure. While "p->member" will be 
interpreted as "p" being the pointer to the structure and "member" being 
the structure itself or the element of the structure. In one case, "p" is
the structure and in another a pointer to the structure. Compiler must know
what is what since it has to allocate the space accordingly.

jsp@sp7040.UUCP (John Peters) (08/08/88)

In article <16734@adm.ARPA>, stanonik@nprdc.arpa (Ron Stanonik) writes:
> While explaining pointers to structures someone asked why
> the -> operator was needed; ie, why couldn't the members be
> referenced as p.member.

It needs to be referenced as a pointer.  To do that use:

		*p.member

it is the same as

		p->member

				--  Johnnie  --

merlyn@intelob.intel.com (Randal L. Schwartz @ Stonehenge) (08/09/88)

In article <474@sp7040.UUCP>, jsp@sp7040 (John Peters) writes:
| In article <16734@adm.ARPA>, stanonik@nprdc.arpa (Ron Stanonik) writes:
| > While explaining pointers to structures someone asked why
| > the -> operator was needed; ie, why couldn't the members be
| > referenced as p.member.
| 
| It needs to be referenced as a pointer.  To do that use:
| 
| 		*p.member
| 
| it is the same as
| 
| 		p->member

Whup.  Not quite.  *p.member is *(p.member).  Try (*p).member instead.
That's one reason the -> syntax was introduced (from what I remember
in reading the white Bible) -- to prevent having to do a lot of parens
for a fairly common operation.  Another example: can you imagine
typing (*((ARR)+(x+y))) every time you wanted ARR[x+y]?

But, the real question (as far as it has been discussed in lang.c, I
guess) is "if only pointers are used in ->, and structs in ., howcum
the compiler can't figure it out?"

Because, it is not PL/1.  I don't want an automatic conversion.  If I
type something like

   indexvalues[j]->fred[3] += 17

I want to be warned if I forgot that indexvalues is really an array of
structs, not array of pointer to struct.  Automatic adjustment could
lead to maintenance headaches later, or even debugging headaches
before it works the first time.

Just an opinion.  But then again, most of what get said here is. :-)
-- 
Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095
on contract to BiiN Technical Publications (for now :-), Hillsboro, Oregon
<merlyn@intelob.intel.com> or ...!tektronix!ogcvax!omepd!intelob!merlyn
Standard disclaimer: I *am* my employer!

ark@alice.UUCP (08/10/88)

In article <474@sp7040.UUCP>, jsp@sp7040.UUCP writes:
> It needs to be referenced as a pointer.  To do that use:
> 
> 		*p.member
> 
> it is the same as
> 
> 		p->member

I'm going to ignore the original question and merely point out that

		*p.member

means the same as

		*(p.member)

which, in turn, is quite different from

		p->member

In fact,

		p->member

means the same thing as

		(*p).member

maart@cs.vu.nl (Maarten Litmaath) (08/10/88)

In article <474@sp7040.UUCP> jsp@sp7040.UUCP (John Peters) writes:
\		*p.member
\
\it is the same as
\
\		p->member

(*p).member, please.
Back to Basic on your C64, Buddy.
-- 
If you enjoyed the recent heat wave,  |Maarten Litmaath @ Free U Amsterdam:
you'll certainly like the ozone gap...|maart@cs.vu.nl, mcvax!botter!maart

chris@mimsy.UUCP (Chris Torek) (08/10/88)

[I am moving this discussion to comp.lang.c]

>In article <16734@adm.ARPA> stanonik@nprdc.arpa (Ron Stanonik) writes:
>>While explaining pointers to structures someone asked why
>>the -> operator was needed; ie, why couldn't the members be
>>referenced as p.member.

In article <474@sp7040.UUCP> jsp@sp7040.UUCP (John Peters) writes:
>It needs to be referenced as a pointer.

True; but to restate the question, `why does not p.member follow
the pointer automagically?'

>*p.member ... is the same as p->member

(Someone else---ark@alice?---already corrected this, but here it is
again:)  No, they are not the same.  In particular, * has lower
precedence than ., but -> has higher precedence than .:

	*p.member	equiv		*(p.member)
	p->member	equiv		(*p).member
	*p->member	equiv		*(p->member)
			etc.

Back to the original question, `why can't you use p.member?'  The
answer is `because it is defined that way'---there is (now) no
particular reason for the definition, and in some other languages
(Mesa) pointer.member is perfectly legal and automagically follows the
pointer before selecting the member.  Some people dislike this magic,
although it is inherently safe (i.e., as long as the compiler is
working, it will never do the wrong thing, since not following the
pointer is always wrong).  That is a matter of style, about which I
shall follow the Roman expression and disputandem not.

Was there ever a reason?  Yes.  Before C became strongly typed,
the `. member' operation simply computed the address of the
object on the left hand side of the `.', looked up the `member'
name in a single global table[*], and added the offset for `member'
to the address of the LHS, then grabbed the object residing
in that location.  Hence you could write such nonsense as

	float f;
	struct {
		int sign1_exp8_mant7;	/* ... bits each */
	};
	f = 123.45;
	printf("exponent = %d\n", (f.sign1_exp8_mant7 >> 7) & 0377);

Similarly, if you had a pointer and wanted the low byte, you could
write

	/* remember, pdp-11 is little-endian */
	struct foo { char lowbyte; char highbyte; } *p;
	lb = p.lowbyte;

and the compiler would cheerfully extract the low byte of the
pointer itself.  If you wanted the low byte of the object to
which p pointed, you had to write (*p).lowbyte or p->lowbyte.
-----
[*] Back then all structures shared the member namespaces.
    This is, at least in part, the root of the format
    `struct garbleblotzer { int gb_thisfield, gb_thatfield; }'
    where an abbreviated version of the name (`gb') appears in
    front of every member.  This served to distinguish between
    members of different structures that would otherwise have
    had the same name.  With the long-since introduction of
    separate name spaces for each structure, this is no longer
    necessary, but I happen to like this format anyway, since
    the member name helps the reader remember the structure name.
-----

Incidentally, the floating point `nonsense' above survives to
this day in the 4.3BSD VAX version of `adb'.  In 4.3BSD-tahoe it
has been `legitimised' as

	(*(struct bad_programming *)&f).selector

which still shows its history.  I recently replaced the whole mess
with a union (`in which', he says, watching the wheel whirl, `each
member is at offset zero . . .').
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

dg@lakart.UUCP (David Goodenough) (08/11/88)

From article <474@sp7040.UUCP>, by jsp@sp7040.UUCP (John Peters):
> In article <16734@adm.ARPA>, stanonik@nprdc.arpa (Ron Stanonik) writes:
>> While explaining pointers to structures someone asked why
>> the -> operator was needed; ie, why couldn't the members be
>> referenced as p.member.
> 
> It needs to be referenced as a pointer.  To do that use:
> 		*p.member
> it is the same as
> 		p->member

Not quite - the correct form is:
 		(*p).member
Check P. 49 of the gospel according to Kernighan and Ritchie for reasons.
However this all explains what it is all about (for more info see
K&R P. 122)
-- 
	dg@lakart.UUCP - David Goodenough		+---+
							| +-+-+
	....... !harvard!cca!lakart!dg			+-+-+ |
						  	  +---+

jerry@olivey.olivetti.com (Jerry Aguirre) (08/11/88)

In article <16734@adm.ARPA> stanonik@nprdc.arpa (Ron Stanonik) writes:
>While explaining pointers to structures someone asked why
>the -> operator was needed; ie, why couldn't the members be
>referenced as p.member.

Now that everyone has explained what the difference between p. and p->
is and what they each mean (which he alread knew), how about answering
the question?

As a precedent the compiler already handles this type of conversion for
arrays.  I can declare:

	char b1[10];
	char *b2;

and then later refer to both of them as:
	
	b1[2] = b2[2];

Now one of these is the actual array and the other is a pointer.  The
compiler has to generate the same type of derefferencing that it would
for a structure refference.

I have had real trouble trying to explain this difference to novice C
programmers.  In particular the difference between:

	extern char *b1;
    and
	extern char b1[];

seems to confuse anyone used to a higher level language.  Many will
insist that the manual says they mean the same thing.

Getting back to structures though.  The final point is that if the
compiler can tell the difference then it is one less detail for the
programmer to worry about.  As long as old code would still work then
there should be no problem, right?
				Jerry Aguirre

greim@sbsvax.UUCP (Michael Greim) (08/11/88)

In article <16734@adm.ARPA>, stanonik@nprdc.arpa (Ron Stanonik) writes:
>While explaining pointers to structures someone asked why
>the -> operator was needed; ie, why couldn't the members be
>referenced as p.member.  My first response was, we're talking
>about pointers to structures, not structures, so a separate
>operator is needed.  On second thought though, since the
>compiler knows whether the variable is a pointer or structure,
>why shouldn't the compiler do the "right" thing when it sees
>p.member?
>
>Could this ever be ambiguous?  That is, is there some declaration
>of p such that p could be interpreted as both a structure and
>a pointer to a separate structure.  I tried fiddling around
>with unions, but could not produce such an object.
Yes, there is something which the compiler cannot decide.
Suppose you have a function
	a (s)
	struct some_struct s;
and you want to call it. So you say
	struct some_struct * s;
	...
	a (s);

What should the compiler do? Do you want the pointer by itself or
do you want to pass the structure s is pointing to?
In a the compiler must know what the parameters will be like.
It will have problems if the declaration of a is not in the same file
as the call.

Or suppose you do
	struct some_struct * s;
	...
	p = &s;
Do you want the address of s or of the structure s is pointing at ?

Or course one could devise some clever algorithm which elaborates on
"if a pointer happens to come along in a function call then
create and pass a record which holds a flag, so that the called function can
tell looking at its parameters what it really has been called with and
convert and copy the real actual parameter accordingly."
(If you are running VMS you get those nifty descriptors by which
a called function really sees what is passed. Or so the theory seems
to go. Overhead, if you ask me. In each program I write under VMS I
stumble across some case where I have to outwit this mechanism.
I would not be anstonished to hear that in VMS C the actual parameters
are passed as descriptors pointing at descriptors pointing at ...  :-)

But such a concept is
- difficult to remember : what do you expect, how often will you
	be wondering : "is the compiler really doing what I think it is ?"
	(Also called the "I wanted this ADA program to count to 10 and now
	it is sending my filled out tax forms to 20.000  people ???"-syndrom :-)
- confusing : it makes one confuse pointers with structures. And sometimes
	you need to understand the differences to know what the program does.
- generating difficulties in the compiler
- making programs more difficult to understand

To conclude : it might be possible, but what would it be worth?

	-mg
-- 
+------------------------------------------------------------------------------+
| UUCP:  ...!uunet!unido!sbsvax!greim   | Michael T. Greim                     |
|        or greim@sbsvax.UUCP           | Universitaet des Saarlandes          |
| CSNET: greim%sbsvax.uucp@Germany.CSnet| FB 10 - Informatik (Dept. of CS)     |
| ARPA:  greim%sbsvax.uucp@uunet.UU.NET | Bau 36, Im Stadtwald 15              |
| Phone: +49 681 302 2434               | D-6600 Saarbruecken 11, West Germany |
+------------------------------------------------------------------------------+
| # include <disclaimers/std.h>                                                |
+------------------------------------------------------------------------------+

barmar@think.COM (Barry Margolin) (08/12/88)

In article <3740@omepd> merlyn@intelob.intel.com (Randal L. Schwartz @ Stonehenge) writes:
]But, the real question (as far as it has been discussed in lang.c, I
]guess) is "if only pointers are used in ->, and structs in ., howcum
]the compiler can't figure it out?"
]Because, it is not PL/1.  I don't want an automatic conversion.

Ahem!  PL/I refuses to do this particular conversion, too.  In fact, I
think PL/I originated the "->" syntax for pointers (did Algol-60 have
pointers?).

Barry Margolin
Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

gwyn@smoke.ARPA (Doug Gwyn ) (08/12/88)

In article <25559@think.UUCP> barmar@kulla.think.com.UUCP (Barry Margolin) writes:
>(did Algol-60 have pointers?).

Yes, but they weren't typed.

What does this have to do with UNIX?