views:

540

answers:

4

Hi everyone, even though it is possible to write generic code in C using void pointer(generic pointer), I find that it is quite difficult to debug the code since void pointer can take any pointer type without warning from compiler. (e.g function foo() take void pointer which is supposed to be pointer to struct, but compiler won't complain if char array is passed.) What kind of approach/strategy do you all use when using void pointer in C?

+2  A: 

This might help:

comp.lang.c FAQ list · Question 4.9

Q: Suppose I want to write a function that takes a generic pointer as an argument and I want to simulate passing it by reference. Can I give the formal parameter type void **, and do something like this?

void f(void **);
double *dp;
f((void **)&dp);

A: Not portably. Code like this may work and is sometimes recommended, but it relies on all pointer types having the same internal representation (which is common, but not universal; see question 5.17).

There is no generic pointer-to-pointer type in C. void * acts as a generic pointer only because conversions (if necessary) are applied automatically when other pointer types are assigned to and from void * 's; these conversions cannot be performed if an attempt is made to indirect upon a void ** value which points at a pointer type other than void . When you make use of a void * pointer value (for instance, when you use the * operator to access the void * value to which the void ** points), the compiler has no way of knowing whether that void * value was once converted from some other pointer type. It must assume that it is nothing more than a void *; it cannot perform any implicit conversions.

In other words, any void ** value you play with must be the address of an actual void * value somewhere; casts like (void *)&dp, though they may shut the compiler up, are nonportable (and may not even do what you want; see also question 13.9). If the pointer that the void * points to is not a void *, and if it has a different size or representation than a void *, then the compiler isn't going to be able to access it correctly.

To make the code fragment above work, you'd have to use an intermediate void * variable:

double *dp;
void *vp = dp;
f(&vp);
dp = vp;

The assignments to and from vp give the compiler the opportunity to perform any conversions, if necessary.

Again, the discussion so far assumes that different pointer types might have different sizes or representations, which is rare today, but not unheard of. To appreciate the problem with void ** more clearly, compare the situation to an analogous one involving, say, types int and double, which probably have different sizes and certainly have different representations. If we have a function

void incme(double *p)
{
    *p += 1;
}

then we can do something like

int i = 1;
double d = i;
incme(&d);
i = d;

and i will be incremented by 1. (This is analogous to the correct void ** code involving the auxiliary vp.) If, on the other hand, we were to attempt something like

int i = 1;
incme((double *)&i);    /* WRONG */

(this code is analogous to the fragment in the question), it would be highly unlikely to work.

Robert S. Barnes
A: 

We all know that the C typesystem is basically crap, but try to not do that... You still have some options to deal with generic types: unions and opaque pointers.

Anyway, if a generic function is taking a void pointer as a parameter, it shouldn't try to dereference it!.

fortran
+6  A: 

The solution is not to use void* unless you really, really have to. The places where a void pointer is actually required are very small: parameters to thread functions, and a handful of others places where you need to pass implementation-specific data through a generic function. In every case, the code that accepts the void* parameter should only accept one data type passed via the void pointer, and the type should be documented in comments and slavishly obeyed by all callers.

JSBangs
The OP specifically mentioned generic programming, which is a pretty good use case for void* (in the absence of higher level language facilities like templates or nice macros.)
Matt Curtis
I mean, for example, qsort() and bsearch()
Matt Curtis
@Matt, qsort and bsearch are examples of "implementation-specific data through a generic function".
JSBangs
@JS: Right, and when you're doing generic programming, the number of places you need to do that is closer to a truck full than a handful ;-)
Matt Curtis
A: 

The approach/strategy is to minimize use of void* pointers. They are needed in specific cases. If you really need to pass void* you should pass size of pointer's target also.

Andrey