[comp.lang.c] accessing initial common structure members

kozak@grad2.cis.upenn.edu (Chuck Kozak) (10/21/90)

I have seen code where the first N members of different structures
are accessed by code that treats the structures as identical.  I
looked through K&R II to check whether this practice is legal and
cannot find any mention of it.  This practice works with GNU C on a
SUN-4 and I cannot think of a reason why it would not work on other
architectures, but I would like to know whether it is a safe or bad
practice.
 
An example of what I mean is given below.
 
struct common {
	struct common *next;
	struct common *prev;
	int type;
};
 
struct type_1 {
	struct common *next;
	struct common *prev;
	int type;
	... type_1 specific members ...
};
 
struct type_2 {
	struct common *next;
	struct common *prev;
	int type;
	... type_2 specific members ...
};
 
void common_function(struct common *pnt)
{
	... access the next, prev, and type members ...
}
 
... other code ...
   struct type_1 type_1_data;
 
   common_function((struct common *) &type_1_data);
...
 
thanks for your help,
 
Chuck Kozak
kozak@grad2.cis.upenn.edu

henry@zoo.toronto.edu (Henry Spencer) (10/21/90)

In article <31468@netnews.upenn.edu> kozak@grad1.cis.upenn.edu (Chuck Kozak) writes:
>I have seen code where the first N members of different structures
>are accessed by code that treats the structures as identical.  I
>looked through K&R II to check whether this practice is legal and
>cannot find any mention of it...

ANSI C promises that this will work only when all the structures in
question are within a union.  (Sufficiently determined theological
reasoning might possibly demonstrate that this suffices to guarantee
it everywhere.)  It is dubious practice at best.
-- 
The type syntax for C is essentially   | Henry Spencer at U of Toronto Zoology
unparsable.             --Rob Pike     |  henry@zoo.toronto.edu   utzoo!henry

richard@aiai.ed.ac.uk (Richard Tobin) (10/23/90)

In article <1990Oct21.051028.11018@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:
> It is dubious practice at best.

This technique is often used where an object may be of several different
kinds, with a type field to distinguish them.  For example:

   enum type {number, cons};

   struct number {enum type type; int value;};
   struct cons   {enum type type; union obj *car, *cdr;}; 

   union obj {struct number; struct cons;};

An alternative, of course, is to do it like this:

   struct number {double value;};
   struct cons   {struct obj *car, *cdr;};

   struct obj {enum type type; 
               union {struct cons cons; struct number number;} value;};

But if you want to allocate only the necessary amount of space when
creating a "number" object, the first form is simpler (you allocate
sizeof(struct number) and cast its address to a (union obj *), whereas
with the second form I think you would have to use something like
offsetof(struct obj, value) + sizeof(struct number)).

I would be interested to hear of elegant, portable ways to do this.

-- Richard
-- 
Richard Tobin,                       JANET: R.Tobin@uk.ac.ed             
AI Applications Institute,           ARPA:  R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk
Edinburgh University.                UUCP:  ...!ukc!ed.ac.uk!R.Tobin