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