Void* Problem in BT

Chris Torek torek at elf.ee.lbl.gov
Sat Mar 2 12:49:11 AEST 1991


(catching up on old news, Feb 6?!)

In article <43818 at nigel.ee.udel.edu> boutell at freezer.it.udel.edu
(Tom Boutell) writes:
>void broadcast(messagetype,details)
>  char messagetype;
>  void* details;
>{

>... [when using `details'] some folks' C compilers report that details
>is undefined and give up.

>Can anyone explain why this is so?

Easy :-)

The people whose compilers say

	"foo.c", line 1234: details undefined

are using versions of PCC (or descendents thereof) in which the `void'
type's number is unchanged since `void' was first added to the compiler
(`void' appeared in 4.0BSD but not in 3BSD, for instance.)

Whoever originally added `void' added it as a special case, and gave it
a type number that corresponds to `UNDEF'.  (Actually, it got a
slightly schizophrenic type; TVOID is FTN while void is UNDEF; but
this is a different problem entirely.)  The variable declaration code
is careful to reject `void' variables:

	if( type == UNDEF ) uerror("void type for %s",p->sname);

but it does not check for pointers to UNDEF as generated by INCREF(UNDEF)
(actual value 020) or pointers to pointers to void (INCREF(INCREF(UNDEF))),
etc.

Now, the symbol table code uses a special value, TNULL, to mark slots in
the symbol table that are free.  TNULL is defined as an `impossible'
type:

	#define	TNULL PTR /* ptr to UNDEF */

The actual value of TNULL is 020---the same value as produced by

	INCREF(UNDEF)

which is the value produced for a declaration of the form:

	void *p;

In other words, in these PCC-based compilers, `void *p;' carefully
allocates a symbol table entry, sets up sizes, offsets, and so forth,
and then sets the symbol table's type to a value meaning `this symbol
table slot is empty'.  When you ask for the name, the symbol table
hashing code dutifully locates the proper slot and sees TNULL and says,
`oh, this slot is empty; I guess the name was not defined after all'.

The right fix for the compiler is somewhat complicated.  The workaround
is simpler, but `#define void char' is NOT it.

One straightforward workaround is to define:

	typedef void *PTR;

or

	typedef char *PTR;

and then use `PTR' exclusively to obtain a generic pointer.  You must
also add casts:

	f(p) PTR p; {
		struct foo *actual;
		...
		actual = p;
	}

will produce at least a warning if `PTR' is an alias for `char *':

		actual = (struct foo *)p;

suppresses this.
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab EE div (+1 415 486 5427)
Berkeley, CA		Domain:	torek at ee.lbl.gov



More information about the Comp.unix.programmer mailing list