Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.2 9/18/84; site brl-tgr.ARPA Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!godot!harvard!seismo!brl-tgr!tgr!cottrell@nbs-vms.ARPA From: cottrell@nbs-vms.ARPA Newsgroups: net.lang.c Subject: type punning Message-ID: <8125@brl-tgr.ARPA> Date: Thu, 7-Feb-85 22:54:00 EST Article-I.D.: brl-tgr.8125 Posted: Thu Feb 7 22:54:00 1985 Date-Received: Sun, 10-Feb-85 04:10:23 EST Sender: news@brl-tgr.ARPA Organization: Ballistic Research Lab Lines: 87 /* As promised, a good reason for type punning. We start off with the definition of basic doubly linked circular lists: typedef struct link { /* list entry */ struct link *fwd; /* foreward pointer */ struct link *bwd; /* backward pointer */ } LINK, *LINKP; typedef struct head { /* list head */ LINK link; /* obvious */ int cnt; /* how many in list */ char id[3]; /* general use */ char lock; /* for test & set */ } HEAD, *HEADP; Now we define other objex such as buffers & channels: typedef struct buf { LINK link; /* to buffers */ .... /* more declarations */ char data[SIZE]; /* data goes here */ } BUF, *BUFP; typedef struct chan { /* com channel */ LINK link; /* to other channels */ .... /* other stuff */ HEAD rcvq; /* to buffers */ HEAD xmtq; /* to buffers */ .... /* other stuff */ LINK misc; /* to other channels */ .... /* chained for some reason */ } CHAN, *CHANP; Notice that the first two items of any struxure are forward & backward links! Now we create two funxions to manipulate links only. They are modeled after the vax instruxions INSQUE & REMQUE: LINKP remque(LINKP p); /* remove p from list */ { if (p) (p->fwd->bwd = p->bwd)->fwd = p->fwd; return(p); } LINKP insque(LINKP p,LINKP q); /* insert p after q */ { if (p) (((p->fwd = q->fwd)->bwd = p)->bwd = q)->fwd = p; return(p); } At the next level we have four funxions that insert & remove `objex' to/from the head/tail of the list: LINKP Get_Head(HEADP h); /* get from head of list h */ { if (!h || !h->cnt) return(0); /* null protect */ --h->cnt; /* one less */ return(remque(h->link.fwd); /* remove the head */ } LINKP Get_Tail(HEADP h); /* get from tail of list h */ { if (!h || !h->cnt) return(0); /* null protect */ --h->cnt; /* one less */ return(remque(h->link.bwd); /* remove the tail */ } LINKP Put_Head(HEADP h,LINKP p); /* put p to head of list h */ { if (!h) return(0); /* null protect */ ++h->cnt; /* one more */ return(insque(h->link.fwd,p); /* put to head */ } LINKP Put_Tail(HEADP h,LINKP p); /* put p to tail of list h */ { if (!h) return(0); /* null protect */ ++h->cnt; /* one more */ return(insque(h,p); /* put to tail */ } The Put funxions return a value so one can move an entire list by: while (Put_Tail(free,Get_head(list)); Note the lack of cast on h in Put_Tail. And for those of you who like out of bounds array refs, note that head->id[3] is available to use if the particular list is never locked via test and set. Now in the modules where we deal primarily with buffers, Get_Head is declared as BUFP Get_Head; where we deal with channels, CHANP Get_Head. And where widgets are used Get_Head is of type WIDGETP. And so on. Lint will go bonkers over this! I for one can do without all those extra casts cluttering up my code. Pretty soon programmers, like actors will be saying: "Break a leg!" */