What Is Void* and to What Variables/Objects It Can Point To

What is void* and to what variables/objects it can point to

void* is such a pointer, that any pointer can be implicitly converted to void*.

For example;

int* p = new int;
void* pv = p; //OK;
p = pv; //Error, the opposite conversion must be explicit in C++ (in C this is OK too)

Also note that pointers to const cannot be converted to void* without a const_cast

E.g.

const int * pc = new const int(4);
void * pv = pc; //Error
const void* pcv = pc; //OK

Hth.

What does void* mean and how to use it?

A pointer to void is a "generic" pointer type. A void * can be converted to any other pointer type without an explicit cast. You cannot dereference a void * or do pointer arithmetic with it; you must convert it to a pointer to a complete data type first.

void * is often used in places where you need to be able to work with different pointer types in the same code. One commonly cited example is the library function qsort:

void qsort(void *base, size_t nmemb, size_t size, 
int (*compar)(const void *, const void *));

base is the address of an array, nmemb is the number of elements in the array, size is the size of each element, and compar is a pointer to a function that compares two elements of the array. It gets called like so:

int iArr[10];
double dArr[30];
long lArr[50];
...
qsort(iArr, sizeof iArr/sizeof iArr[0], sizeof iArr[0], compareInt);
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareDouble);
qsort(lArr, sizeof lArr/sizeof lArr[0], sizeof lArr[0], compareLong);

The array expressions iArr, dArr, and lArr are implicitly converted from array types to pointer types in the function call, and each is implicitly converted from "pointer to int/double/long" to "pointer to void".

The comparison functions would look something like:

int compareInt(const void *lhs, const void *rhs)
{
const int *x = lhs; // convert void * to int * by assignment
const int *y = rhs;

if (*x > *y) return 1;
if (*x == *y) return 0;
return -1;
}

By accepting void *, qsort can work with arrays of any type.

The disadvantage of using void * is that you throw type safety out the window and into oncoming traffic. There's nothing to protect you from using the wrong comparison routine:

qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareInt);

compareInt is expecting its arguments to be pointing to ints, but is actually working with doubles. There's no way to catch this problem at compile time; you'll just wind up with a missorted array.

void pointer vs object in function parameters

A pointer refers to a variable.

An instance of object refers to a value.

This is a very key difference. Using a pointer you can mutate another variable (usually one that's not currently in scope). Using an object instance you can only ever mutate a value, possibly one that another variable also reference, but that's still a key difference.

Because the pointer refers to a variable, mutations to the referred to variable variable will be observable through the pointer. The pointer is also capable of mutating that variable. An object instance on the other hand is not tied to another variable. Even if the object it refers to is referred to by another variable, changes in that other variable won't be observable through the object instance, and it also has no way of mutating the other variable.

There's also the fact that for an object to reference a value type that value type needs to be boxed. This can have performance implications in that the values end up being copied, but also significant semantic differences. Mutations of the source variable won't be visible to the object reference, while they would be had you used a void pointer.

Why use a void pointer for dereferencing variables of datatypes?

A void pointer is a generic pointer which can hold the address of any type and can be typecast to any type.

In the first case, the program successfully compiled and ran without any warning or error, because using a void pointer to convert from one pointer type to another and then storing or casting it to the final type is safe without losing data.

But in the second case the GCC compiler generated a warning

prog.c: In function 'main':
prog.c:5:9: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
int *ip=&a;
^

clang compiler:

warning: incompatible pointer types initializing 'int *' with an expression of type 'float *' [-Wincompatible-pointer-types]
int *ip=&a;
^ ~~

The C11 Standard, 6.3.2.3, paragraph 7:

A pointer to an object or incomplete type may be converted to a
pointer to a different object or incomplete type. If the resulting
pointer is not correctly aligned for the referenced type, the behavior
is undefined.



Related Topics



Leave a reply



Submit