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