[comp.lang.c] why p->member ?

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

karl@haddock.ISC.COM (Karl Heuer) (08/11/88)

In article <12937@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>to restate the question, `why does not p.member follow the pointer
>automagically?'  [Historical reason deleted]

People have enough trouble with the difference between pointers and arrays.
If `.' and `->' were the same operator, they'd have a similar difficulty
understanding the difference between structs and struct pointers.

Also, even those of us who understand the difference are likely to make a typo
now and then.  I prefer my typos to elicit an error message from the compiler,
rather than silently guessing what I meant.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

neitzel@infbs (Martin Neitzel) (08/13/88)

btw, the debugger "dbx" will dereference a structure pointer p
automatically in an expression like "p.a"

And just another remark regarding the operator "->":

I for one would enjoy a corresponding assignment augmentation
for it:  "node ->= next".  (But then, I like things like APL,
you know...)

							Martin
Martin Neitzel,  Techn. Univ. Braunschweig, W.Germany
BITNET/EARN:	neitzel@dbsinf6.bitnet	  (mail via bitnet preferred)
UUCP:		neitzel@infbs.uucp  (unido!infbs!neitzel)
from ARPA:	neitzel%dbsinf6.bitnet@psuvax1.psu.edu

karl@haddock.ISC.COM (Karl Heuer) (08/16/88)

In article <968@infbs.UUCP> neitzel@infbs (Martin Neitzel) writes:
>I for one would enjoy a corresponding assignment ... "node ->= next".

It could be done, but it doesn't really fit well into the language.  "->"
isn't an binary operator in the usual sense, since its right operand isn't
an expression.  Similarly, you can't write "x -=" to mean "x = -x".

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
(Yes, the above can be written "x *= -1", but that's not the point.)