The Important But Restricted Role Void Pointers Should Play in Your Code

Last modified by Microchip on 2024/01/19 14:50

A pointer in the C language allows you to indirectly access objects via their address and is fully described on the data pointers page. The type of a pointer is derived from the type of the object that the pointer can reference. This ensures that the size and storage format of the referenced object is known, so, for example, a pointer defined with the type int * can reference int objects.

When you don’t know the type of the object whose address is held by a pointer or a pointer has to be able to reference several objects with different types, the referenced type of that pointer can be set to void, as in void *. Pointers to void—void pointers, or generic pointers as they used to be called—are intended to be used as temporary storage for addresses, most often as function parameters or for function return values. The malloc() library function is an example of a function that returns a void pointer since it does not know what sort of objects will be stored in the memory it allocates.

Void pointer variables can be assigned an address and their content can be copied to other pointers, but you should never write code that manipulates void pointers. In particular, you should never attempt to perform pointer arithmetic on void pointers as the results are undefined. Pointer arithmetic is primarily intended to allow a pointer which is referencing an element in an array to be incremented or decremented so that it can point to other elements in the same array. Pointer arithmetic relies on being able to take the size of the referenced object and since taking the size of a void object is undefined behavior, pointer arithmetic on void pointers makes no sense.

As soon as possible and before they are used, your code should convert the values held by void pointers to pointers with an appropriate referenced type, either by assigning them to a regular object pointers or casting them to the required type.

Here is a typical implementation of a function that compares each byte of the objects referenced by the two void pointer parameters, ptr1 and ptr2. These void pointers are implicitly converted and assigned to char pointers, p1 and p2 by the function. Note that it is only the char pointers that are dereferenced and incremented in this code. However, by using void pointer parameters, this function can be used to compare the bytes of objects with any type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int memcmp(const void * ptr1, const void * ptr2, unsigned count)
{
   const unsigned char * p1 = ptr1;
   const unsigned char * p2 = ptr2;

   while(count-- != 0) {
       if(*p1 != *p2)
               return *p1 - *p2;
        p1++;
        p2++;
    }

   return 0;
}

Back to Top