txlutera@crdc.arpa (Thomas Luteran) (12/11/85)
I have a problem with a header file that contains typedefs similar to those below in that both contain a reference to the other. The problem stems from the fact second structure will be undefined (not properly defined) when the first typedef tries to reference it: typedef struct car { int numdoors; char color[8]; char owner[20]; . . . struct garage *parked; <- using LOT here for struct garage won't struct car *next; } AUTO; work! typedef struct garage { char location[20]; . . . struct car *customers; struct garage *next; } LOT; Please send any replies directly to me - Thanks in advance! Tom
gwyn@BRL.ARPA (VLD/VMB) (12/11/85)
The approved way to declare two structs each of which has a member that is a pointer to the other type of struct, is: struct a; struct b { struct *a; }; struct a { struct *b; }; Yes, I know it looks unbelievable. This kludge is present precisely to handle this kind of problem.
gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (12/11/85)
OOPS! Please ignore my previous posting on this, which had the member types misdeclared. The idea was right but I was distracted while typing it. Here is the correct version: The approved way to declare two structs each of which has a member that is a pointer to the other type of struct, is: struct a; struct b { struct a *ap; /* BUG FIX */ }; struct a { struct b *bp; /* BUG FIX */ }; Yes, I know it looks unbelievable. This kludge is present precisely to handle this kind of problem.
chris@umcp-cs.UUCP (Chris Torek) (12/12/85)
Ai! Doug, how could you? You posted an example that is not even syntactically correct! C compilers are obliged by K&R to accept declarations of pointers to structure types even if those structure types have not yet been declared. That is, the following is legal: /* * Doubly linked list of node headers */ struct nodehead { struct nodehead *nh_next; struct nodehead *nh_prev; struct node *nh_front; /* <1> */ }; /* * Singly linked nodes with backpointers to the node header */ struct node { struct node *n_next; struct nodehead *n_head; /* <2> */ . . . }; If you intend to use anonymous structures and typedefs, e.g., typedef struct { ... } NODEHEAD; you still need a name for at least one of the two structures, as C compilers are allowed to be `one pass' and cannot infer that a name is a typedef that has yet to be compiled. At least one of the two marked references (<1> and <2>) must be to a `struct foo *', since at least one will be a forward reference no matter how you organise the declarations. I would check my X3J11 draft to see what it says, but someone `cleaned up' my desk. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu
draves@harvard.UUCP (Richard Draves) (12/12/85)
In general it is important to include the 'forward declaration':
struct a;
struct b { struct a *pa; };
struct a { struct b *pb; };
This makes a difference when the declarations are inside a scope
that already can see a definition of 'struct a'. For instance,
struct a { ... };
main()
{
struct b { struct a *pa; };
struct a { struct b *pb; };
...
}
does not do what one might expect.
Rich
--
"a picture in the head is a gory murder in an art gallery"
-- Stephen Kosslyn
mouse@mcgill-vision.UUCP (der Mouse) (12/13/85)
> I have a problem with a header file that contains typedefs similar > to those below in that both contain a reference to the other. > [example, similar to:] > typedef struct a { struct b *b; } A; > typedef struct b { struct a *a; } B; Well, what I would do is struct a { struct b { struct a *a; } *b; }; typedef struct a A; typedef struct b B; I don't believe you can make it recognize forward references in general. You certainly can't do it for direct elements, because the compiler doesn't know the size of the member, and you can't do it for pointers because architectures might (do?) exist out there for which not all pointers are the same size (yes, I too think anyone who designs such a machine as "general purpose" should be forced to write the C compiler for it themselves; it might teach them something). So you certainly can't forward reference the typedefs. On some machines you might be able to forward reference the structure, provided you use a pointer to it (does X3J11 have anything to say about this?). Someone mentioned that a kludge had been put in so you could get around this with struct b; struct a { struct b *b; }; struct b { struct a *a; }; Ugh. Speaking of structures containing self-referential pointers, I once wrote some code which used the following structures: struct _coord { struct _coord *flink; struct _coord *blink; int val; int index; struct _boxlist { struct _boxlist *link; struct _box { struct _box *flink; struct _box *blink; int number; struct _coord *lx; struct _coord *ux; struct _coord *ly; struct _coord *uy; } *box; } *boxes; }; Three structures, a total of 14 structure elements, and only three elements which aren't just a pointer to another structure. (Okay, okay, I'll put it in net.jokes.c next time, I promise...) -- der Mouse USA: {ihnp4,decvax,akgua,etc}!utcsri!mcgill-vision!mouse philabs!micomvax!musocs!mcgill-vision!mouse Europe: mcvax!decvax!utcsri!mcgill-vision!mouse mcvax!seismo!cmcl2!philabs!micomvax!musocs!mcgill-vision!mouse Hacker: One who accidentally destroys / Wizard: One who recovers it afterward
geoff@desint.UUCP (Geoff Kuenning) (12/14/85)
People who want to write maximally portable should also note the following technique, so that they can avoid it: typedef struct foo *ZAP; typedef struct bar *ZOW; struct foo { ZOW *zowie; }; struct bar { ZAP zapped; }; Since pcc (and, I believe, the original pdp-11 compiler) treats typedefs as macros, this works on those compilers. However, it breaks lint, and it breaks on many compilers that actually treat typedefs as types, since the structs are undefined at the time of the typedef statement. -- Geoff Kuenning {hplabs,ihnp4}!trwrb!desint!geoff