A void* does not mean anything. It is a pointer, but the type that it points to is not known.
It's not that it can return "anything". A function that returns a void* generally is doing one of the following:
- It is dealing in unformatted memory. This is what
operator newandmallocreturn: a pointer to a block of memory of a certain size. Since the memory does not have a type (because it does not have a properly constructed object in it yet), it is typeless. IE:void. - It is an opaque handle; it references a created object without naming a specific type. Code that does this is generally poorly formed, since this is better done by forward declaring a struct/class and simply not providing a public definition for it. Because then, at least it has a real type.
- It returns a pointer to storage that contains an object of a known type. However, that API is used to deal with objects of a wide variety of types, so the exact type that a particular call returns cannot be known at compile time. Therefore, there will be some documentation explaining when it stores which kinds of objects, and therefore which type you can safely cast it to.
This construct is nothing like dynamic or object in C#. Those tools actually know what the original type is; void* does not. This makes it far more dangerous than any of those, because it is very easy to get it wrong, and there's no way to ask if a particular usage is the right one.
And on a personal note, if you see code that uses void*'s "often", you should rethink what code you're looking at. void* usage, especially in C++, should be rare, used primary for dealing in raw memory.
What is a void pointer in C++? - Stack Overflow
Are void * pointers meant for generic typing in C? - Stack Overflow
generic programming in C with void pointer - Stack Overflow
Is there such a thing as a generic function pointer in C that can be assigned/cast to a more restrictive prototype? - Stack Overflow
What is the difference between a general pointer and a void pointer in C?
Is there any difference between the null pointer and the void pointer in C?
Why do we use a void pointer in C programs?
Videos
A void* does not mean anything. It is a pointer, but the type that it points to is not known.
It's not that it can return "anything". A function that returns a void* generally is doing one of the following:
- It is dealing in unformatted memory. This is what
operator newandmallocreturn: a pointer to a block of memory of a certain size. Since the memory does not have a type (because it does not have a properly constructed object in it yet), it is typeless. IE:void. - It is an opaque handle; it references a created object without naming a specific type. Code that does this is generally poorly formed, since this is better done by forward declaring a struct/class and simply not providing a public definition for it. Because then, at least it has a real type.
- It returns a pointer to storage that contains an object of a known type. However, that API is used to deal with objects of a wide variety of types, so the exact type that a particular call returns cannot be known at compile time. Therefore, there will be some documentation explaining when it stores which kinds of objects, and therefore which type you can safely cast it to.
This construct is nothing like dynamic or object in C#. Those tools actually know what the original type is; void* does not. This makes it far more dangerous than any of those, because it is very easy to get it wrong, and there's no way to ask if a particular usage is the right one.
And on a personal note, if you see code that uses void*'s "often", you should rethink what code you're looking at. void* usage, especially in C++, should be rare, used primary for dealing in raw memory.
Void is used as a keyword. The void pointer, also known as the generic pointer, is a special type of pointer that can be pointed at objects of any data type! A void pointer is declared like a normal pointer, using the void keyword as the pointer’s type:
General syntax:
void* pointer_variable;
void *pVoid; // pVoid is a void pointer
A void pointer can point to objects of any data type:
int nValue;
float fValue;
struct Something
{
int nValue;
float fValue;
};
Something sValue;
void *pVoid;
pVoid = &nValue; // valid
pVoid = &fValue; // valid
pVoid = &sValue; // valid
However, because the void pointer does not know what type of object it is pointing to, it can not be dereferenced! Rather, the void pointer must first be explicitly cast to another pointer type before it is dereferenced.
int nValue = 5;
void *pVoid = &nValue;
// can not dereference pVoid because it is a void pointer
int *pInt = static_cast<int*>(pVoid); // cast from void* to int*
cout << *pInt << endl; // can dereference pInt
Source: link
The purpose of a void * is to provide a welcome exception to some of C's typing rules. With the exception of void *, you cannot assign a pointer value of one type to an object of a different pointer type without a cast - for example, you cannot write
int p = 10;
double *q = &p; // BZZT - cannot assign an int * value to a double *
When assigning to pointers of different types, you have to explicitly cast to the target type:
int p = 10;
double *q = (double *) &p; // convert the pointer to p to the right type before assigning to q
except for a void *:
int p = 10;
void *q = &p; // no cast required here.
In the old days of K&R C, char * was used as a "generic" pointer type1 - the memory allocation functions malloc/calloc/realloc all returned char *, the callback functions for qsort and bsearch took char * arguments, etc., but because you couldn't directly assign different pointer types, you had to add an explicit cast (if the target wasn't a char *, anyway):
int *mem = (int *) malloc( N * sizeof *mem );
Using explicit casts everywhere was a bit painful.
The 1989/1990 standard (C89/C90) introduced the void data type - it's a data type that cannot store any values. An expression of type void is evaluated only for its side effects (if any)2. A special rule was created for the void * type such that a value of that type can be assigned to/from any other pointer type without need of an explicit cast, which made it the new "generic" pointer type. malloc/calloc/realloc were all changed to return void *, qsort and bsearch callbacks now take void * arguments instead of char *, and now things are a bit cleaner:
int *mem = malloc( sizeof *mem * N );
You cannot dereference a void * - in our example above, where q has type void *, we cannot get at the value of p without a cast:
printf( "p = %d\n", *(int *)q );
Note that C++ is different in this regard - C++ does not treat void * specially, and requires an explicit cast to assign to different pointer types. That's because C++ provides overloading mechanisms that C doesn't.
- Every object type should be mappable to an array of
char. - In K&R C, all functions had to return a value - if you didn't explicitly type the function, the compiler assumed it returned
int. This made it difficult to determine which functions were actually meant to return a value vs. functions that only had side effects. Thevoidtype was handy for typing functions that weren't meant to return a value.
C suffers from the absence of function overloading. So most C "generic" functions as for example qsort or bsearch use pointers to void * that to be able to deal with objects of different types.
In C you need not to cast a pointer of any type to a pointer of the type void *. And a pointer of any type can be assigned with a pointer of the type void * without casting.
So in C the functions from your code snippet can be rewritten like
void store(struct GenericStruct *strct, int *myarr){
strct->ptr = myarr;
}
int *load(struct GenericStruct *strct){
return strct->ptr;
}
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.
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.
The C standard guarantees that any object pointer type can be converted to void* and back again without loss of information (meaning that the re-converted pointer will compare equal to the original one).
There is a different guarantee for function pointers: Any function pointer can be converted to any other function pointer type and back again without loss of information.
(There is no guarantee regarding conversions between function pointers and object pointers, or more specifically between function pointers and void*. An implementation could, for example, make void* 64 bits and function pointers 128 bits.)
You can use, for example, void(*)(void) as a generic function pointer type:
typedef void (*funcptr)(void);
You must convert back to the original pointer type before executing a call to avoid undefined behavior.
On the other hand, you're using dlsym(), which returns a void*. My understanding is that POSIX guarantees that the void* returned by dlsym() (if the name argument names a function) can be converted to a function pointer, which can be used to call the function. If the only functions you care about are those whose addresses are returned by dlsym(), then you can use void*.
(POSIX previously guaranteed, as an extension to the C standard, that a function pointer can be converted to void* and back again. That guarantee was later dropped. Thanks to Jonathan Leffler for pointing this out.)
In any case, using function pointers to store the addresses of functions probably makes for clearer code.
dlsym returns a data pointer of type void *, but POSIX guarantees that this can be cast to a function pointer of the appropriate type:
Implementations supporting the XSI extension [...] require that an object of type
void *can hold a pointer to a function. The result of converting a pointer to a function into a pointer to another data type (exceptvoid *) is still undefined, however.
Since Version 7 of POSIX, all implementations (not just XSI) are required to support the conversion.
Because conversion from a void * pointer to a function pointer via a direct cast can result in compiler warnings, older versions of POSIX recommend performing the conversion via aliasing:
int (*fptr)(int);
*(void **)(&fptr) = dlsym(handle, "my_function");
In the current version the recommendation is changed to:
int (*fptr)(int);
fptr = (int (*)(int))dlsym(handle, "my_function");