why p->member ?

Chris Torek chris at mimsy.UUCP
Wed Aug 10 16:14:46 AEST 1988


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

>In article <16734 at adm.ARPA> stanonik at 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 at sp7040.UUCP> jsp at 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 at 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 at mimsy.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.unix.questions mailing list