[comp.lang.c] Structure Pointer Question

andrew@teletron.UUCP (Andrew Scott) (06/10/88)

I have a question regarding pointers to structures and their use in data
structure definitions found in #include files.

Suppose I wish to declare a commonly used data structure, which has as one
of its fields a pointer to a less often used structure.  I wish to define
the structure "templates" in different #include files:

foo.h:					bar.h:

struct bar;				struct bar {
						...
struct foo {				};
	...
	struct bar *f_b;
};

Is it alright to #include "foo.h" and not "bar.h" in a source file if the
fields of "struct bar" are not used?  I would think that it would be fine
as long as pointers to structs are all the same "flavor".  The compiler
I'm using doesn't mind.

I suppose I could #include both if I had to, but I'd rather not because of
modularity reasons.  I'm just wondering what the usual practice is.
-- 
Andrew Scott		andrew@teletron.uucp    - or -
			{att, ubc-cs, watmath, ..}!alberta!teletron!andrew

gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/11/88)

In article <361@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) writes:
>Is it alright to #include "foo.h" and not "bar.h" in a source file if the
>fields of "struct bar" are not used?

Technically not, because the "struct foo" type remains incomplete until
you declare a complete type for "struct bar".  The easiest thing to do
is to have "foo.h" include "bar.h" right after the incomplete "struct foo"
declaration.  Then the application doesn't have to worry about it.

As you noticed, sometimes you can get away without doing it right.

karl@haddock.ISC.COM (Karl Heuer) (06/13/88)

In article <8074@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn) writes:
>In article <361@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) writes:
>>Is it alright to #include "foo.h" and not "bar.h" in a source file if the
>>fields of "struct bar" are not used?

I believe the answer is Yes.  (As noted, it depends on all struct pointers
having the same format, but this is implicitly required by the language.)

>Technically not, because the "struct foo" type remains incomplete until
>you declare a complete type for "struct bar".

I hate to contradict Doug, but I believe that (a) he's wrong, and (b) even if
he's right, it doesn't matter.

(a) struct foo was defined to contain a *pointer* to a struct bar, not an
actual struct bar.  A type is incomplete only if its size is unknown; this is
true of bar, but not foo.

(b) There's no rule that forbids having incomplete types in a program.  They
only need to be completed if the missing information is required.  The
incomplete type (obtained by including foo.h) and the complete type (obtained
by also including bar.h) are compatible types.

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

sullivan@vsi.UUCP (Michael T Sullivan) (06/14/88)

In article <8074@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
> In article <361@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) writes:
> >Is it alright to #include "foo.h" and not "bar.h" in a source file if the
> >fields of "struct bar" are not used?
>
> you declare a complete type for "struct bar".  The easiest thing to do
> is to have "foo.h" include "bar.h" right after the incomplete "struct foo"
> declaration.  Then the application doesn't have to worry about it.

Which brings up a question:  is it considered a good thing or a bad thing
to have .h files #include'ing other .h files instead of having the .c files
do it all.  The rule around here is that there are to be no #include's in
.h files we write.  Mail me your opinions for or against.

-- 
Michael Sullivan		{uunet|attmail}!vsi!sullivan
V-Systems, Inc.  Santa Ana, CA	sullivan@vsi.com
HE V MTL			<-That's my license plate, is yours any better?

eric@snark.UUCP (Eric S. Raymond) (06/14/88)

In article <4524@haddock.isc.com>, Karl Heuer writes:
>In article <361@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) writes:
>>Is it alright to #include "foo.h" and not "bar.h" in a source file if the
>>fields of "struct bar" are not used?
>
>There's no rule that forbids having incomplete types in a program.  They
>only need to be completed if the missing information is required.  The
>incomplete type (obtained by including foo.h) and the complete type (obtained
>by also including bar.h) are compatible types.

Would that it were so! Unfortunately this usage (i.e. specification of an
`incomplete' type with a pointer component that references an unspecified type,
in hopes the compiler will just say "oh, this is a pointer" compile in a
pointer-sized slot and not complain) is *not* portable.

In particular, it choked some early System V Release 1 compilers (the same
ones that enforced a def-ref extern model and required full specification of
union members) and upsets some MS-DOS compilers, especially in mixed-model
environments where the size of pointer-to-unknown-thing is unobvious. I know
old Lattices had this problem; I'm not sure if Microsoft C still does or not.

On some of these compilers, the right thing to do is precede your incomplete
declaration with a stub that declares the unknown thing without specifying
members, i.e.

struct unknown;

struct linklist
{
    /* value parts */

    struct unknown *link;
};

I think this will work on any UNIX compiler. But this corner of the portability
problem is really murky and obscure; I've just had to develop ways of avoiding
such constructions (this is moderately painful, because my C style is LISP-
influenced and leans heavily on list and graph-like structures).

-- 
      Eric S. Raymond                     (the mad mastermind of TMN-Netnews)
      UUCP: {{uunet,rutgers,ihnp4}!cbmvax,rutgers!vu-vlsi,att}!snark!eric
      Post: 22 South Warren Avenue, Malvern, PA 19355   Phone: (215)-296-5718

karl@haddock.ISC.COM (Karl Heuer) (06/18/88)

In article <dPHjH#3yOH86=eric@snark.UUCP> eric@snark.UUCP (Eric S. Raymond) writes:
>In article <4524@haddock.isc.com>, Karl Heuer writes:
>>There's no rule that forbids having incomplete types in a program.  They
>>only need to be completed if the missing information is required.
>
>Would that it were so! Unfortunately this usage (i.e. specification of an
>`incomplete' type with a pointer component that references an unspecified
>type, in hopes the compiler will just say "oh, this is a pointer" compile in
>a pointer-sized slot and not complain) is *not* portable.

It's not a pointer to a completely unspecified type.  It's a pointer to a
struct with unknown contents.  (This matters.  Although pointer-to-char and
pointer-to-int might have different internal representations, pointer-to-
-struct-foo and pointer-to-struct-bar cannot%.)

>On some of these compilers, the right thing to do is precede your incomplete
>declaration with a stub that declares the unknown thing without specifying
>members, i.e.
>   struct unknown;
>   struct linklist { ...; struct unknown *link; };

This contains no more information than without the stub, so I fail to see why
the compiler should care.  My view is that such a compiler is broken.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
% I believe this can be proved using the dpANS, and probably just from K&R.

firth@sei.cmu.edu (Robert Firth) (06/18/88)

In article <4606@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) writes:

>It's not a pointer to a completely unspecified type.  It's a pointer to a
>struct with unknown contents.  (This matters.  Although pointer-to-char and
>pointer-to-int might have different internal representations, pointer-to-
>-struct-foo and pointer-to-struct-bar cannot%.)

This makes no sense to me.  Surely a pointer to a struct whose only
component is of type X will use the same representation as a pointer
to a plain X.  Hence if *X and *Y differ, so will *struct{X} and
*struct{Y}.

throopw@xyzzy.UUCP (Wayne A. Throop) (06/20/88)

> firth@sei.cmu.edu (Robert Firth)
>> karl@haddock.ima.isc.com (Karl Heuer)
>>Although pointer-to-char and
>>pointer-to-int might have different internal representations, pointer-to-
>>-struct-foo and pointer-to-struct-bar cannot%.
> This makes no sense to me.  Surely a pointer to a struct whose only
> component is of type X will use the same representation as a pointer
> to a plain X.  Hence if *X and *Y differ, so will *struct{X} and
> *struct{Y}.

Actually, I think you're both wrong.  Sort of.

First, a pointer to a struct containing only a char and a pointer to a
char needn't have the same format to be standard conforming.  In fact,
DG's C compiler does this very thing: pointer-to-char and
pointer-to-struct-containing-only-a-char have different formats.  

But on the other hand, I'm not aware of any requirement in draft X3J11
that all struct pointers have the same format.  It is a good idea to
make it so, because of quite a bit of existing code, and so many
compilers do, indeed, make it so.  But they needn't, as far as I know.

In a footnote in Karl's posting, he said that he thought he could
construct an argument that draft X3J11 does indeed require this.  I'd be
interested to see this argument... As I said, I don't see how it could
be constructed.  But, as always, I could be missing some fine print.

--
"You don't think my theory holds water?"
"A bathtub will hold water.  A canteen is usually sufficent."
        --- exchange between Laurent Michaelmas and Domino
-- 
Wayne Throop      <the-known-world>!mcnc!rti!xyzzy!throopw

karl@haddock.ISC.COM (Karl Heuer) (06/20/88)

In article <5925@aw.sei.cmu.edu> firth@bd.sei.cmu.edu.UUCP (Robert Firth) writes:
>Surely a pointer to a struct whose only component is of type X will use the
>same representation as a pointer to a plain X.

Nope.  The fact that incomplete types are allowed in some circumstances (e.g.
the existence of mutually recursive types) implies that all struct pointers
have to smell the same.  Thus, on word-addressible machines, struct{char} is
word-aligned and padded.  (Or else all structs use byte-pointers, but I don't
believe I've heard of such implementations.)

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

sullivan@vsi.UUCP (Michael T Sullivan) (06/20/88)

In article <718@vsi.UUCP>, sullivan@vsi.UUCP (Michael T Sullivan) writes:
> Which brings up a question:  is it considered a good thing or a bad thing
> to have .h files #include'ing other .h files instead of having the .c files
> do it all.  The rule around here is that there are to be no #include's in
> .h files we write.  Mail me your opinions for or against.

Thanks to the many people who responded.  I've had quite a busy mailbox
this past week.

The majority of replies said that if a .h file depends on another .h file,
then the #include should be in the .h file so the .c files don't have to
worry about figuring out the interdependencies.

What to do to avoid accidentally #include'ing a .h file twice?  You do this
by clever usage of the pre-processor:

/* header.h */
#ifndef	_HEADER_H
#define	_HEADER_H	1

#include	"something.h"

...stuff...

#endif	/* _HEADER_H */

(This same arrangement is in something.h)

This will allow file.c to #include header.h only, as well as #include
something.h before header.h without any problems.  Note the leading
underscore in the name-macro _HEADER_H.  This keeps your namespace from
being polluted.

This type of thing sure would be handy in the Unix header files (hint, hint).
Thanks again for all replies.

-- 
Michael Sullivan			{uunet|attmail}!vsi!sullivan
V-Systems, Inc.  Santa Ana, CA		sullivan@vsi.com
ons, workstations, workstations, workstations, workstations, workstations, work

jimp@cognos.uucp (Jim Patterson) (06/20/88)

In article <5925@aw.sei.cmu.edu> firth@bd.sei.cmu.edu.UUCP (Robert Firth) writes:
>In article <4606@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) writes:
>
>>It's not a pointer to a completely unspecified type.  It's a pointer to a
>>struct with unknown contents.  (This matters.  Although pointer-to-char and
>>pointer-to-int might have different internal representations, pointer-to-
>>-struct-foo and pointer-to-struct-bar cannot%.)
>
>This makes no sense to me.  Surely a pointer to a struct whose only
>component is of type X will use the same representation as a pointer
>to a plain X.

Either approach is valid. A 'correct' program should not assume that a
pointer-to-struct-foo and pointer-to-struct-bar are equivalent.  The
compiler is therefore free to use different representations. However,
on most machines the compiler design is simplified by using a common
representation, so in practice the representations are often made
equivalent.

An example of a compiler which makes all struct pointers equivalent is
the DG C compiler. The DG systems are word-oriented (a byte address is
2* the word address, with the extra low-order bit used to address the
byte in the word). However, all struct addresses are word addresses,
even if they only contain char data. In this case, the cost is only at
most a single byte per struct, and only in the relatively obscure
cases where a struct consists only of some odd number of bytes of char
data. The benefit in simplicity of both the compiler and of programs
which use it makes up for this slight cost.

A counter-example is the HP SPECTRUM C compiler. The Spectrum is a
RISC architecture which has strict alignment rules (e.g. 32-bit ints
need 32-bit alignment, 64-bit floats need 64-bit alignment).  The C
compiler of course ensures this when it allocates its data, but to
avoid excessive memory wastage it computes the appropriate alignment
for structs on a case by case basis. A struct can therefore have
anywhere from 8-bit to 64-bit alignment depending on contents. This
won't cause representational problems on the Spectrum because pointers
are all effectively byte pointers (only the number of forced low order
0-bits varies). However, it can result in problems if you assume that
a struct with a smaller alignment can be replaced by one with a larger
alignment. For example, the following code segment could blow up or
could work depending on whether Foo happened to be aligned on an even
or odd 32-bit boundary.

    struct foo { long a,b; } Foo;
    struct bar { double c; };
    ((struct bar *)&Foo)->c = 5.0;

The bottom line is that strictly speaking, you should not assume that
different struct pointers have the same representation. In practice,
you will usually get away with it, but someday you may get bit.
-- 
Jim Patterson                              Cognos Incorporated
UUCP:decvax!utzoo!dciem!nrcaer!cognos!jimp P.O. BOX 9707    
PHONE:(613)738-1440                        3755 Riverside Drive
                                           Ottawa, Ont  K1G 3Z4

gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/21/88)

In article <723@vsi.UUCP> sullivan@vsi.UUCP (Michael T Sullivan) writes:
>Note the leading underscore in the name-macro _HEADER_H.  This keeps
>your namespace from being polluted.

Be careful!  That identifier is reserved for use by the (ANSI) C
implementation and should not be used by applications.

In a large application we're currently developing, there are many
functional "packages", each of which has its own 2-letter prefix
which is used for all external identifiers in the package, as well
as all macros defined in the corresponding interface definition
header.  So, for example, our header "Dx.h" uses the name
"Dx_HDR_INCLUDED" for its one-time lockout flag.  This package
prefix scheme also addresses the problem of namespace partitioning,
and has been working out quite well.

>This type of thing sure would be handy in the Unix header files (hint, hint).

A start had already been made at doing this, and it is essential for
ANSI C conformance.  (The C implementation will have to use macro
names starting with underscore for its lockout flags.)

bill@proxftl.UUCP (T. William Wells) (06/29/88)

Having reread the new C standard just to see what it says about
incomplete types relating to structure pointers, here is what I
come up with.

There is nothing wrong with a source file like:

	struct {
		struct bar *ptr;
	} x;
	func()
	{
		void *vp;

		vp = (void *)x.ptr;
		vp = 0;
	}

Nothing in the standard seems to require completing the type
unless the pointer is actually dereferenced.

Furthermore, since the assignments are valid (see 3.3.16.1), this
implies that the compiler knows the internal representation of
the structure pointer even if it does not know the contents of
the structure. There are only two ways that I can think of to
accomplish this: make all structure pointers equivalent or defer
code generation till link time.  I would be extremely surprised
(read, "what reality are YOU in?") if they want to require the
latter, so it must be the former.

The C standard should make that explicit, don't you think?

gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/30/88)

In article <389@proxftl.UUCP> bill@proxftl.UUCP (T. William Wells) writes:
>The C standard should make that explicit, don't you think?

It's been known for many years that the logic of C requires that
structure pointers all "smell the same" in a certain sense (for
example, in the context of sizeof).  However, they definitely do
NOT have to have the same representation.  For example, in a C
interpreter they could contain tag information that could be used to
distinguish between them (presumably to detect usage errors).

andrew@teletron.UUCP (Andrew Scott) (06/30/88)

In article <389@proxftl.UUCP>, bill@proxftl.UUCP (T. William Wells) writes:
> Having reread the new C standard just to see what it says about
> incomplete types relating to structure pointers, here is what I
> come up with.
> 
> Nothing in the standard seems to require completing the type
> unless the pointer is actually dereferenced.

Now that my original question has been answered, I have another:

Suppose that I've constrcuted a library of functions that operate on a
"generic" data structure called 'struct message'.  This structure is an
incomplete type; the library functions merely deal with pointers to this
structure but not with the fields within.

It is now permissible to use this library with different declarations of
'struct message' *in the same program*?  I'm not planning on converting
between multiple kinds of "messages", I just want to have multiple modules
in the program able to use the previously constructed library with data
structures applicable to (and used in) only one module.

My initial guess is that it would work, given that C requires all structure
pointers to have the same format and provided that I compile the different
modules of the program seperately (so that the compiler doesn't see the
multiple declarations).
-- 
Andrew Scott		andrew@teletron.uucp    - or -
			{codas, ubc-cs, watmath, ..}!alberta!teletron!andrew

bill@proxftl.UUCP (T. William Wells) (07/05/88)

In article <391@teletron.UUCP>, andrew@teletron.UUCP (Andrew Scott) writes:
> Now that my original question has been answered, I have another:
>
> Suppose that I've constrcuted a library of functions that operate on a
> "generic" data structure called 'struct message'.  This structure is an
> incomplete type; the library functions merely deal with pointers to this
> structure but not with the fields within.
>
> It is now permissible to use this library with different declarations of
> 'struct message' *in the same program*?  I'm not planning on converting
> between multiple kinds of "messages", I just want to have multiple modules
> in the program able to use the previously constructed library with data
> structures applicable to (and used in) only one module.
>
> My initial guess is that it would work, given that C requires all structure
> pointers to have the same format and provided that I compile the different
> modules of the program seperately (so that the compiler doesn't see the
> multiple declarations).

Strictly speaking, such a program does not have to work,
however...

I pointed out that, unless some code generation is done at link
time, a compiler can't really make assumptions about incomplete
structure types and thus can't use different representations for
structure pointers; however, another message points out that
there is one relatively common environment where this is not
true: interpreters. I'd say that, if you are using a system with
separately compiled modules that what you are doing is likely to
work, but if you did it in a interpreter system, that it may not.

Also, I know of one compiler system that could defer part of the
code generation to link time. The Amsterdam Compiler Kit's
program building goes compile, link, and assemble; the linker can
fix up structure pointer references if necessary.  The compiler
used for MINIX is based on this compiler system.

The correct solution is to have your library deal with void *.
If a raw void * bothers you, use typedef void *MESSAGE; and then
type everything as MESSAGE. You will also probably want to have
macros that do the references to library functions if these
pointers are to be passed as arguments or returned as values by
functions in the library.

I'll guess that you are building some kind of message passing
system and that your library has something to do with queueing
and dequeing. On that presumption, here is how I might write an
enqueue function.

These are in the public include file:

	#define msg_queue(x) (lib_msg_queue((void *)(x)))
	extern int      lib_msg_queue();
	extern void     *msg_dequeue();

These are in the library itself:

	typedef struct Q_ELT {
		struct Q_ELT *q_next;
		void    *q_message;
	} Q_ELT;

	int
	lib_msg_queue(msg)
	void    *msg;
	{
		Q_ELT   *qptr;

		if (!(qptr = (Q_ELT *)malloc(sizeof(Q_ELT)))) {
			return (-1);
		}
		qptr->q_message = msg;
		...enqueue the message
		return (0);
	}

	void *
	msg_dequeue()
	{
		Q_ELT   *qptr;
		void    *msg;

		qptr = ... dequeue the message;
		if (!qptr) {
			return (0);
		}
		msg = qptr->q_message;
		free(qptr);
		return (msg);
	}

If you have a compiler with prototypes, your job is even easier.
Change the name of lib_msg_queue to msg_queue and place this in
the public include file:

	extern int      msg_queue(void *msg);
	extern void     *msg_dequeue(void);

Does that help?

andrew@teletron.UUCP (Andrew Scott) (07/07/88)

In article <424@proxftl.UUCP>, bill@proxftl.UUCP (T. William Wells) writes:
> In article <391@teletron.UUCP>, andrew@teletron.UUCP (Andrew Scott) writes:

[ about an idea I had to use incomplete structure definitions as generic data
  structures ]

> The correct solution is to have your library deal with void *.
> If a raw void * bothers you, use typedef void *MESSAGE; and then
> type everything as MESSAGE.

Indeed, I have been informed that this is the only truly portable way of doing
things.  HOWEVER, I do not have a compiler that supports "void *" at the
moment, and I cannot stand seeing lint all hot and bothered about casts to
and from "char *".  :-)

Terrible reasons, I know, but it does look "cleaner" than using void * (to me,
at least) and I think it *would* be portable if all pointers to structures
had the same format.
-- 
Andrew Scott		andrew@teletron.uucp    - or -
			{codas, ubc-cs, watmath, ..}!alberta!teletron!andrew

bill@proxftl.UUCP (T. William Wells) (07/11/88)

In article <399@teletron.UUCP>, andrew@teletron.UUCP (Andrew Scott) writes:
> In article <424@proxftl.UUCP>, bill@proxftl.UUCP (T. William Wells) writes:
> > The correct solution is to have your library deal with void *.
> > If a raw void * bothers you, use typedef void *MESSAGE; and then
> > type everything as MESSAGE.
>
> Indeed, I have been informed that this is the only truly portable way of doing
> things.  HOWEVER, I do not have a compiler that supports "void *" at the
> moment, and I cannot stand seeing lint all hot and bothered about casts to
> and from "char *".  :-)
>
> Terrible reasons, I know, but it does look "cleaner" than using void * (to me,
> at least) and I think it *would* be portable if all pointers to structures
> had the same format.

As I have come to see, while it is the case that structure
pointers are somewhat equivalent, in the same way that constant
zero and null pointers are somewhat equivalent, they do not have
to have the same format. As I said, this is likely to work but
not guaranteed, since while most implementations have all
structure pointers with the same format, there is nothing that
requires this.

Were I you, I'd first try to get a new compiler, and failing
that, I'd live with the messages from lint.  If I really
couldn't hack that, I'd create some programming to filter out
the irrelevant complaints from lint.

Also, to save yourself some grief, should you decide to go the
char * route, write them as VOID * (or even void * if you are
not afraid of getting a compiler that will barf on that) and use
a typedef. This will save you headaches when you switch
compilers. It might also make the programming mentioned in the
previous paragraphs easier.

dmg@ssc-vax.UUCP (David Geary) (07/12/88)

In article <391@teletron.UUCP>, andrew@teletron.UUCP (Andrew Scott) writes:
> Now that my original question has been answered, I have another:
>
> Suppose that I've constrcuted a library of functions that operate on a
> "generic" data structure called 'struct message'.  This structure is an
> incomplete type; the library functions merely deal with pointers to this
> structure but not with the fields within.
>
> It is now permissible to use this library with different declarations of
> 'struct message' *in the same program*?  I'm not planning on converting
> between multiple kinds of "messages", I just want to have multiple modules
> in the program able to use the previously constructed library with data
> structures applicable to (and used in) only one module.
>
> My initial guess is that it would work, given that C requires all structure
> pointers to have the same format and provided that I compile the different
> modules of the program seperately (so that the compiler doesn't see the
> multiple declarations).

  Well, I went through this kind of thing a couple of years ago while
developing a "psuedo-object-oriented" system.  Here's how I implemented it:

  First, let's describe a "struct Object":

  struct Object {
                   int  Type;  
		   char *Name;
                   
		   struct Object  *Parent;
		   struct Object  *Next;
		   struct Object  *Previous;

		   OBJECT_UNION  objs;
                 };
  
  typedef struct Object OBJECT;

  Parent, Next, and Previous, as you can probably guess, are linkages in
a tree structure, where "Objects" are stored. (By the way, in my implementation
each node in the tree can have any number of children, each of which can
have any number of children, etc).  
  I've also included a Type field, and a name for each object.
  The OBJECT_UNION is:

  typedef union {
		   THIS_TYPE_OF_OBJECT   *this.id;
		   THAT_TYPE_OF_OBJECT   *that.id;
		   ANOTHER_TYPE_OBJECT   *another.id;
                }
		   OBJECT_UNION;

  Where, of course, THIS_TYPE_OF_OBJECT, THAT_TYPE_OF_OBJECT, etc. are
all typedefs of structures.

  Now, you can write routines to manipulate OBJECTs, without regard to
what member is "alive" in the union.  You can compile the routines,
and put them in a library.

  The only problem you run into is with allocation.  When you create a
"new type" of OBJECT, you have to change the definition of the
OBJECT_UNION:

  typedef union {
		  THIS_TYPE_OF_OBJECT  *this.id;
		  THAT_TYPE_OF_OBJECT  *that.id;
		  ANOTHER_TYPE_OBJECT  *another.id;
		  NEWLY_CREATED_OBJECT *new.id;     /* here's new one */
                }
		  OBJECT_UNION;

and, you must add code to a function that allocates OBJECTS.  Here's
an example of the allocation routine:

#define MALLOC(type,num)   (type *)malloc(sizeof(type)*num)

OBJECT *CreateObject(type,name)
  int type;
  char *name;
{
  OBJECT *new;

  if( new = MALLOC(OBJECT, 1); 
  {
    new->Type = type;
    new->Name = malloc(strlen(name) + 1);
    strcpy(new->Name, name);

    switch(type)
    {
      case THIS_TYPE_OF_OBJECT_ID:  
      
      new->objs->this.id = MALLOC(THIS_TYPE_OF_OBJECT, 1);
			   /* Allocate specifics of THIS_TYPE_OF_OBJECT here */
			   break;
      
      /* ADD CODE FOR "NEW" OBJECT HERE */ 
    }
  }
}

When you create a new type of OBJECT, you simply add another statement to
the switch.

  Well, I don't know how clear all of this is, it's about time for me
to get off (of work, that is) ;-).  However, it really is a powerful
tool - here's an example of some source I wrote for developing pop-up
menus:


/****  MenuExample.c:  

  This program demonstrates the use of "ObjectTrees".
  See the files:  ObjectsStandard.h, ObjectsUserDefined.h to see
  the definition of Menus and Menu Items.

  This file creates data structures for pop-up menus, and links
  the data structures in a tree structure.
****/

#include <stdio.h>
#include "ObjectTrees.h"

CreateMenus(Top)
  OBJECT *Top;
{
  ObjectStackPush(Top, MENU_OBJ_ID, "Project Menu");
  ObjectStackPush(Top, MENU_OBJ_ID, "Cut And Paste Menu");
  ObjectStackPush(Top, MENU_OBJ_ID, "Extras Menu");
} 

CreateProjectMenuItems(Top)
  OBJECT *Top;
{
  OBJECT *ObjectPointer = ObjectGetNamedChild(Top, "Project Menu"); 

  ObjectEnqueue(ObjectPointer, MENU_ITEM_OBJ_ID, "Read File");
  ObjectEnqueue(ObjectPointer, MENU_ITEM_OBJ_ID, "Write File");
  ObjectEnqueue(ObjectPointer, MENU_ITEM_OBJ_ID, "Delete File");
}

CreateCutAndPasteMenuItems(Top)
  OBJECT *Top;
{
  OBJECT *ObjectPointer = ObjectGetNamedChild(Top, "Cut And Paste Menu");
  
  ObjectAddChild(ObjectPointer, MENU_ITEM_OBJ_ID, 1, "Cut");
  ObjectAddChild(ObjectPointer, MENU_ITEM_OBJ_ID, 2, "Copy");
  ObjectAddChild(ObjectPointer, MENU_ITEM_OBJ_ID, 3, "Paste");
  ObjectAddChild(ObjectPointer, MENU_ITEM_OBJ_ID, 4, "Clear Buffer");
}

CreateExtrasMenuItems(Top)
  OBJECT *Top;
{
  OBJECT *ObjectPointer = ObjectGetNamedChild(Top, "Extras Menu");

  ObjectAddChild(ObjectPointer, MENU_ITEM_OBJ_ID, 1, "Full Screen");
  ObjectAddChild(ObjectPointer, MENU_ITEM_OBJ_ID, 2, "Iconify");
  ObjectAddChild(ObjectPointer, MENU_ITEM_OBJ_ID, 3, "Import Graphics");
  ObjectAddChild(ObjectPointer, MENU_ITEM_OBJ_ID, 4, "High Resolution");
  ObjectAddChild(ObjectPointer, MENU_ITEM_OBJ_ID, 3, "Low Resolution");
}

main()
{
  OBJECT  *TreeTop = ObjectCreateTreeTop(), 
          *ObjectPointer,
          *ObjPoped,
          *ObjDequeued; 

  CreateMenus(TreeTop);
  CreateProjectMenuItems(TreeTop);
  CreateCutAndPasteMenuItems(TreeTop);
  CreateExtrasMenuItems(TreeTop);

  ObjectDoFunctionAllChildren(TreeTop, ObjectPrintPublicData);

  do 
    ObjPoped = ObjectStackPop(ObjectGetNamedChild(TreeTop, "Extras Menu"));
  while(ObjPoped);

  do
    ObjDequeued = ObjectDequeue(ObjectGetNamedChild(TreeTop, "Project Menu"));
  while(ObjDequeued);

  ObjectDoFunctionAllChildren(TreeTop, ObjectPrintPublicData);
}

The above functions create the data structures for menus, and link
them all together.

Note that I have added routines to treat the children of an object as
a stack or queue.

If you have any questions, send me some mail.



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~	"... I live in hotels, tear up the walls."	~
~            I have accountants pay for it all.         ~ 
~							~
~                 Life's Been Good,			~
~                           Joe Walsh                   ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-- 
***********************************************************
* David Geary, Boeing Aerospace Co., Seattle, WA 	  *
* I disclaim all disclaimers....			  *
***********************************************************

chris@mimsy.UUCP (07/12/88)

In article <2080@ssc-vax.UUCP> dmg@ssc-vax.UUCP (David Geary) writes:
>Keywords: You don't really *read* this line, do you?

(Some do!)

>  typedef union {
>		   THIS_TYPE_OF_OBJECT   *this.id;
>		   THAT_TYPE_OF_OBJECT   *that.id;
>		   ANOTHER_TYPE_OBJECT   *another.id;
>                }
>		   OBJECT_UNION;
>
>  Where, of course, THIS_TYPE_OF_OBJECT, THAT_TYPE_OF_OBJECT, etc. are
>all typedefs of structures.

This is what `void *' is for (and if you do not have `void *', `char *'
*probably* works):

	struct object {
		int	type;
		...
		void	*pointer;
	}; ...
		struct some_real_object *p = this_obj->pointer;
		p->real_data = ...;

Without `void *' this must be cast:

		struct some_real_object *p =
		    (struct some_real_object *)this_obj->pointer;
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris