type punning
cottrell at nbs-vms.ARPA
cottrell at nbs-vms.ARPA
Fri Feb 8 13:54:00 AEST 1985
/*
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!"
*/
More information about the Comp.lang.c
mailing list