Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!helios!bcm!rice!uw-beaver!cornell!rochester!uhura.cc.rochester.edu!ub!zaphod.mps.ohio-state.edu!caen!hellgate.utah.edu!dog.ee.lbl.gov!elf.ee.lbl.gov!torek From: torek@elf.ee.lbl.gov (Chris Torek) Newsgroups: comp.unix.programmer Subject: Re: Void* Problem in BT Keywords: C Void Insanity Help! Message-ID: <10501@dog.ee.lbl.gov> Date: 2 Mar 91 01:49:11 GMT References: <43818@nigel.ee.udel.edu> Reply-To: torek@elf.ee.lbl.gov (Chris Torek) Organization: Lawrence Berkeley Laboratory, Berkeley Lines: 85 X-Local-Date: Fri, 1 Mar 91 17:49:11 PST (catching up on old news, Feb 6?!) In article <43818@nigel.ee.udel.edu> boutell@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@ee.lbl.gov