two levels of indirection on a void

Nathan Sidwell nathan@acm.org
Wed Oct 14 01:41:00 GMT 1998


Tel wrote:
> void x( void )
> {
>         void **y;
>         int **z;
> 
>         y = z;
>         z = y;
> }
>[two warnings]
> void x( void )
> {
>         void *y;
>         int *z;
> 
>         y = z;
>         z = y;
> }
>[no warnings] 
> In my opinion both should compile without warnings otherwise the language
> is inconsistent. If this is a bug then I'm reporting it, if it is the
> ANSI standard then someone needs a big kick up the backside (if only I
> knew who :-)
egcs is correct acording to ISO/ANSI C. void is a special case in the
type system which means pointer to void are silently coerced (just like
ints, for instance are silently coerced to longs, as necessary).The
reasons are many and subtle, but here goes,

void is an incomplete type. This means there are no objects of type
void. You cannot write `void i'. A pointer to void (aka a void pointer)
is a complete type -- it's a pointer to an object of unknown/arbitrary
type.

The language guarantees that a pointer to any object type can be
converted to a pointer to void (and back again), without loss of
information. This explains why the second program has no warnings --
there's nothing wrong with it. The compiler inserts the cast, just like
it would up cast a short to an int, in arithmetic expressions (and back
again).

Now in the first example you didn't have a pointer to void, but a
pointer to a pointer to void (or think of it as a pointer to a void
pointer). The other type is a pointer to a pointer to an int (or a
pointer to an int pointer). Silently converting one to the other is bad,
because the representation of a void pointer might not have the same bit
pattern as the representation of an int pointer. for instance
sizeof(void *) might be greater than sizeof(int *), or there might be
type information embeded in the pointer, or ... (those are the kind of
things the standard authors had to think about). The compiler cannot go
in and mangle the void pointer being pointed at into an int pointer as
it would have to to make things consistent -- you'd be surprised if the
assignment of one pointer to another changed the thing being pointed at.

Think of `void' as a hole in the type system, but the hole only is one
level deep. Or think of the base type as `void *', which matches all
other pointer types. The C FAQ says something about this
( http://www.eskimo.com/~scs/C-faq/q4.9.html )

You missed the really confusing case
{
void *vp;
void **pvp;

pvp = vp; /*no warning */
vp = pvp; /* no warning */
}

Things are slightly different with C++. you need an explicit cast going
from void ptr to oject ptr.


nathan

-- 
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
      You can up the bandwidth, but you can't up the speed of light      
nathan@acm.org  http://www.cs.bris.ac.uk/~nathan/  nathan@cs.bris.ac.uk



More information about the Gcc-bugs mailing list