question realted to void *

J

James Kuyper

Chad said:
[...]
And if that is correct, should we ever use void ** ?
void* can be used as a generic pointer type. What that means is that
a value of any pointer type (other than a pointer-to-function type)
can be converted to void* and back again without loss of information.

You might think that void** is therefore a generic pointer-to-pointer
type, but it isn't; in fact, there is no generic pointer-to-pointer
type.

You can convert an int*, or an int**, or an int***, or ... to void*
without loss of information -- except that you lose the type
information, which you have to carefully keep track of yourself.

--

How would you track the type information in this case?

Thats pretty much up to you. There's no way to do it in absolute
generality, but if you have a small list of possibilities that are
relevant to the question, then the following is one example of how to do it:

#include <stdlib.h>
enum typecode { INTP /* many other codes */ };

struct multipointer {
enum typecode pointed_at;
void *pointer;
};

struct multipointer *multipointer_from_intpp(int **ipp)
{
struct multipointer *p = malloc(sizeof *p);
if(p)
{
p->pointed_at = INTP;
p->pointer = ipp;
}
return p;
}

void use_multipointer(struct multipointer *p)
{
if(p==NULL)
return;
switch(p->pointed_at)
{
case INTP:
{
int **ipp = (int **)p->pointer;

// code which works with ipp, such as
if(ipp && ipp[0])
**ipp = 0;
}
break;
// many other cases, including a default:
}
}
 
T

Tim Rentsch

James Kuyper said:
Keith said:
James Kuyper said:
Any pointer to an object type can be converted to void* and
back. However, that does not mean that void* is compatible with all of
those other pointer type; it's only guaranteed to be compatible with
pointers to character types.
[...]

I understand what you mean, but "compatible" isn't the word for it.
The standard has a very specific definition for "compatible types"; by
that definition, void* and char* are not compatible.

C99 6.7.5.1p2:

For two pointer types to be compatible, both shall be identically
qualified and both shall be pointers to compatible types.

Since void and char are not compatible, void* and char* are not
compatible.

You're right: the standard requires them to have the same alignment
requirements and same representation, but they are not compatible
according to C's definition of the term. This is another of those cases
where the standard falls short of actually saying something that I think
it was actually intended to say. As a practical matter, they work just
as if they were compatible, on most implementations.

This reading is overly broad. The statement about having the
same representation and alignment requirements applies /only/
to value of these types, not to types derived from these types.
There isn't any reason to conclude that the standard requires
a (void**) and a (char**) to have the same representation,
or be interchangeable in any other way that compatible types
must be. The same statement holds for function types with
(void *) and (char *) in them.
 
T

Tim Rentsch

Harald said:
You're right: the standard requires them to have the same alignment
requirements and same representation, but they are not compatible
according to C's definition of the term. This is another of those cases
where the standard falls short of actually saying something that I thin= k
it was actually intended to say. As a practical matter, they work just
as if they were compatible, on most implementations.

My compiler reports an error when I try

void f(char *p);
void f(void *p) {}

My compiler doesn't report an error when I try

void f(void *p);
void f(void *p) {}

or when I try

void f(int (*p)[]);
void f(int (*p)[30]) {}

I have trouble believing the intent was to allow the first, or that you
believe that was intended. If char * and void * were compatible, it would
be allowed, because compatible means something different from how you are
using it.

What I meant is a little more complicated than what I said. You can
work around the fact that those functions are incompatible by using
some type punning. The behavior of code that performs such type
punning is undefined, but I believe that it was the intent of the
committee that such type punning would work.

Again, this reading is overly broad, as explained in more detail in my
other responses. The standard does not require, nor does it intend to
require, that values of type (void (*)(char*)) be interchangeable with
values of type (void (*)(void*)). We can pass a (char*) value to
a function that expects a (void*), and it should work; but that
expectation does not extend to derived function types.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top