[comp.lang.c] Unions that generate offsets

crash@jc3b21.UUCP (Frank (Crash) Edwards) (09/11/87)

Okay all, I'm ready for the flames from this one!

Given the following definition, should the reference "msg.m_union.m_from"
be a legal reference to the member of the "pckt" structure?  And should
it reference the first location of m_union or the first location of pckt?
The compiler generated offset for m_from is 0.  Inside a union, all
members have the offset 0.  So "m_union.pckt.m_from" is equivalent to
"m_union.m_from":

	struct {
	    long mtype;			/*  Message type...	*/
	    union {
	 	char	text[80];	/*  For sending textual message	*/
		struct {
		    long   m_from;	/*  Data contained in a packet	*/
		    ushort m_cmnd;
		    char   data[40];
		} pckt;
	    } m_union;
	} msg;

K&R says that the syntax rules for unions are the same as for structures.
And that in a structure reference ('.' or '->') the name on the right *must
be a member* of the structure named or pointed to by the expression on the
left (the accent is mine).

	PP 14.1, K&R:

	"To allow an escape from the typing rules, this restriction is
	not strictly enforced by the compiler.  In fact, any lvalue is
	allowed before ., and that lvalue is then assumed to have the
	form of the structure of which the name on the right is a member."

So what happened to "must be a member"?

	"Such constructions are non-portable."

Which such constructions?  The ones just defined for the '.' member
reference or the ones for '->'?  Or does it matter?

	PP 8.5, K&R:

	"Actually, the compiler checks only that a name in two different
	structures has the same type and offset in both, but if preceding
	members differ the construction is non-portable."

First of all, this paragraph should read, "but if preceding member *types*
differ".  Since the compiler checks offsets, the construction is non-
portable only if the offset might change during porting.  This will not
happen if the preceding *types* remain the same, regardless of whether
they are the same members.  (I know -- a little picky maybe.)

Again the reference "the compiler" -- as if only *one* compiler existed!
Oh well.  If the compiler only checks for type and offset, why should it
care if I use the union member (in this example "m_from") as an offset
to "msg"?  And is this offset non-portable?  After all, I'm using an
offset created by the compiler.  Maybe the term "portable" in paragraph
14.1 actually means "compilable", since the other compiler may not
adhere to K&R?

Well, I'm ready for your opinions...  flames...  experiences...

(I particularly expect to hear from old instructors who thought that they
had taught me better than to write code like that!)

---------------------------------------------------------------------------
Frank J. Edwards, Programmer      UUCP:  codas!usfvax2!jc3b21!tsc3b21!crash
Transportation Systems            Phone: (813) 785-0583
	Consulting Corporation
1680 US Hwy Alternate 19
Palm Harbor, FL  34683

throopw@xyzzy.UUCP (09/12/87)

> crash@jc3b21.UUCP (Frank (Crash) Edwards)

Frank seems confused between what the language guarantees to do, and
what some particular compiler for the language actually does.  Or
perhaps between what programmers programming in a given language must
do, and what compilers for that language must do.

> K&R says that the syntax rules for unions are the same as for structures.
> And that in a structure reference ('.' or '->') the name on the right *must
> be a member* of the structure named or pointed to by the expression on the
> left (the accent is mine).
> 	PP 14.1, K&R:
> 	"To allow an escape from the typing rules, this restriction is
> 	not strictly enforced by the compiler.  In fact, any lvalue is
> 	allowed before ., and that lvalue is then assumed to have the
> 	form of the structure of which the name on the right is a member."
> So what happened to "must be a member"?

Nothing at all.  It still must be a member, in the sense that for a
programmer to be programming in C, that programmer must ensure that it
is in fact a member.  It's just that some (many) compilers don't enforce
this.  An analogy:  "The manager said that I must be a member to enter
the club, but the doorman didn't check my ID.  So what happened to that
'must be a member' stuff?"  What happened to it is nothing at all... if
the manager sees you, he'll be within his rights to boot you out.  The
compiler (doorman) isn't the same thing as the language standard
(manager).  And when some other compiler (doorman) *does* check your
structure usage (ID) and flag it as erronious (boots you out), you can't
point to the first compiler (doorman) as a reason to allow you what you
want.

> 	PP 8.5, K&R:
> 	"Actually, the compiler checks only that a name in two different
> 	structures has the same type and offset in both, but if preceding
> 	members differ the construction is non-portable."
> 
> First of all, this paragraph should read, "but if preceding member *types*
> differ".  Since the compiler checks offsets, the construction is non-
> portable only if the offset might change during porting.  This will not
> happen if the preceding *types* remain the same, regardless of whether
> they are the same members.  (I know -- a little picky maybe.)

In fact, K&R are telling you outright that "this *may* happen" *EVEN*
*IF* the preceeding types are the same.  In other words, K&R said what
they said... there's no "should" about it: they just don't guarantee
what you think is guaranteed.  If you still think it *is* guaranteed,
you must look to some other guarantor than K&R.

> Again the reference "the compiler" -- as if only *one* compiler existed!
> Oh well.  If the compiler only checks for type and offset, why should it
> care if I use the union member (in this example "m_from") as an offset
> to "msg"?

Again, "the compiler" (doorman) doesn't care.  But the language
definition (manager) *does* care, and if you do this, you simply won't
be programming in C.  So there.

--
The place where I come from is a small town.
They think so small, they use small words.
But not me.  I'm smarter than that.  I've worked it out.
I'll stretch my mouth to let those big words come right out.
                        --- from "Big Time" by Peter Gabriel
-- 
Wayne Throop      <the-known-world>!mcnc!rti!xyzzy!throopw

gwyn@brl-smoke.UUCP (09/13/87)

In article <167@jc3b21.UUCP> crash@jc3b21.UUCP (Frank (Crash) Edwards) writes:
>Given the following definition, should the reference "msg.m_union.m_from"
>be a legal reference to the member of the "pckt" structure?

No.  You forgot to include ".pckt" in the reference.

>And should
>it reference the first location of m_union or the first location of pckt?

Assuming you fix that, it references the "m_from" member, naturally.

>	"Such constructions are non-portable."

Yup, they were allowed by a particular implementation of C, not by
the language rules.

>First of all, this paragraph should read, "but if preceding member *types*
>differ".

No, K&R had it right.  If preceding members (member names) differ, the
result is non-portable.  Some compilers won't even allow it.

Why don't you just do this the right way (fully-qualified member path),
rather than try to cheat?

henry@utzoo.UUCP (Henry Spencer) (09/13/87)

> Again [K&R] reference "the compiler" -- as if only *one* compiler existed!

You are forgetting how *old* K&R is.  There *was* only one, for all practical
purposes, when that was written.  (Remember, much of Appendix A predates even
the book's copyright date by quite a bit.)
-- 
"There's a lot more to do in space   |  Henry Spencer @ U of Toronto Zoology
than sending people to Mars." --Bova | {allegra,ihnp4,decvax,utai}!utzoo!henry

peter@sugar.UUCP (09/14/87)

In article <167@jc3b21.UUCP>, crash@jc3b21.UUCP (Frank (Crash) Edwards) writes:
> 	"Actually, the compiler checks only that a name in two different
> 	structures has the same type and offset in both, but if preceding
> 	members differ the construction is non-portable."

> First of all, this paragraph should read, "but if preceding member *types*
> differ".  Since the compiler checks offsets, the construction is non-
> portable only if the offset might change during porting.

> Again the reference "the compiler" -- as if only *one* compiler existed!

The book was written when basically only one compiler existed. The compiler
described is the PDP-11 K&R compiler. Most modern 'C' compilers do check
on the types of the structure and the member and will complain. Thus the
construction is non-portable.

Whenever K&R talks about "the compiler", that should cue you to regard
the associated text as being suspect unless you're using a PDP-11 running
version 6 or version 7 UNIX.
-- 
-- Peter da Silva `-_-' ...!hoptoad!academ!uhnix1!sugar!peter
--                 'U`      ^^^^^^^^^^^^^^ Not seismo!soma (blush)