Thanks for your detailed reply, Keith.
In my humble view, the ideal solution would be:
1) void* is a generic pointer type that can be implicitly converted
to/from any other object that can be dereferenced at least !once!
(e.g. char*, int*, also char**, int**, but not char,int)
2) void** is a generic pointer type [...]
No; stop right there. void** is not at "generic" at all,
not in the least. A void** is a pointer to a void*, and not
a pointer to any other kind of object or function.
Your confusion, perhaps, is this: A void* can point to any
kind of object, and can be converted to and from other object
pointer types without a cast. That's why it's often called
"generic," but the term is really very loose. However, a void*
is itself an object type, a perfectly concrete "real" object
type like an int or a char* or whatever. Just as with other
concrete object types, it's possible to form a pointer to objects
of this void* type. But such a pointer is in no way "generic;"
it can only be NULL or point to an actual void* object somewhere.
> [...] having identified the main cause of entropy (and also
crashes ;-) in my current sources: The inability to safely pass a
pointer to any pointer as a function argument.
That's right. C does not require that all pointers "smell
the same." Pointers to different types can come in different
shapes and sizes, so there's really no such thing as a "generic
pointer" (despite the common sloppy usage of the phrase to
describe void*). You might as well speak of a "generic number;"
just as short and double can look different, short* and double*
can look different.
Typical example: the function mem_freesetnull which frees a pointer and
sets it to NULL (very helpful in the context of exception handling):
Ideally, it would take the address of a pointer as argument and look
like that:
void mem_freesetnull(void **ptradd)
{ mem_free(*ptradd);
*ptradd=NULL; }
Unfortunately, that's not possible, because I'd have to use an ugly
explicit cast to (void**) in every call to the function.
Even the cast will not save you. Just as numbers come in
different flavors, pointers come in different flavors. Just as
you cannot set a number to zero without knowing its type, you
cannot set a pointer to NULL without knowing its type.
So in practice, I have to move the explicit cast to the function
itself:
void mem_freesetnull(void *ptradd)
{ mem_free(*(void**)ptradd);
*(void**)ptradd=NULL; }
Now the function looks ugly, but more importantly, I lost an important
piece of type-safety:
Most important of all, the function is now incorrect.
You seem upset by all the warnings the compilers emit for
constructs of this sort, but it turns out they know C better
than you do: This code is wrong, and the compiler is right
to complain about it.
I'm thinking about a GCC patch for an option to specifically disable
the warning in the cases outlined above. But if that has zero chance of
acceptance, I'll save my time ;-)
While you're at it, disable the diagnostics for unbalanced
parentheses, for `("Hello" / "world!")', and for all the other
programming errors that might be made. The source for gcc is
readily available; you are free to make changes and use your own
version if you choose -- but allow me to suggest that your choice
is ill-informed. In short, you don't know what you're doing; you
don't know C well enough.