Learn what is a void pointer by going through this article. Get to know various applications of this useful pointer variety.
Introduction
Last time, the past blog discussed pointers pointing to values that have specific data types. However, suppose you want to point to a memory location, but don’t know yet what data type it will hold. In this situation, it’s best to use a void pointer.
Void pointers are pointers that don’t need a specific data type. It points to a starting memory location where the value of this memory location can have any type. For example, void pointers can point to a memory location containing ints, chars, arrays, floats, structures, or even functions, to name a few.
You may encounter void pointers in RTOS Embedded Systems or in projects with lots of data structure operations.
Void Pointers Illustrated
The example below illustrates a void pointer variable vptr that can either point to the start of an int or float value. It doesn’t matter how much memory space this value holds. An int might hold two bytes of memory space while a float four. vptr is not declared to point to any type.
How to Declare a Void Pointer
You declare a void pointer variable using the void * type which means there is no actual type.Â
// void pointer variable
void* vptr;
Initializing the Void Pointer
Just like pointers, you can assign a memory location to void pointers that contains an actual value.
Suppose we have defined an X_int int variable or a Y_float float variable:
// integer and float variables
int X_int;
float Y_float;
We can assign the memory location of the said variables to vptr through the address of operator (&) to initialize this pointer.
// initialize the pointer with the addess of the int variable
X_int = 25;
vptr = &X_int;
or:
// initialize the pointer with the address of the float variable
Y_float = 12.05;
vptr = &Y_float;
Use the Value or Dereference the Void Pointer
Last time, our blog introduced dereferencing to use or get the value the pointer is pointing at. However, void pointers should be treated differently. These pointers don’t have any type, so you should explicitly tell the compiler what type you want extracted from them. With this, you must use typecasting.
// typecast the pointer using an int pointer and then derefernce or use its value
A_int = *(int*)vptr;
Above, you’ll see the vptr pointer typecasted using an integer pointer. After that, it is dereferenced to be able to extract or use its value. The same process holds for the float pointer below.
// typecast the pointer using a float pointer and then derefernce or use its value
B_float = *(float*)vptr;
A Working Example Code
Below is the complete working example code for void pointers.
#include
#include
#include
// void pointer variable
void* vptr;
// integer and float variables
int X_int, A_int;
float Y_float, B_float;
void app_main(void)
{
// initialize the pointer with int variable
X_int = 25;
vptr = &X_int;
// typecast the pointer using an int pointer and then derefernce or use its value
A_int = *(int*)vptr;
printf("Int value is %i\r\n", A_int);
// initialize the pointer with int variable
Y_float = 12.05;
vptr = &Y_float;
// typecast the pointer using a float pointer and then derefernce or use its value
B_float = *(float*)vptr;
printf("Float value is %.2f\r\n", B_float);
while(1)
{
vTaskDelay(100);
}
}
Int value is 25
Float value is 12.05
A Practical Example: Choosing Between 8-bit and 16-bit ADC values
Below, you’ll see a practical example of using void pointers. Here, a single function Acquire_ADC( ) that chooses between a 16-bit or 8-bit ADC data acquisition and then displays the result. Two variable structures, ADC_16bits and ADC_8bits were created for this and are passed as function arguments. Since we passed them using void pointers, their data type lengths doesn’t matter.
#include
#include
#include
typedef struct ADC_8bits_tag {
int ADC_res;
uint8_t ADC_data;
} ADC_8bits_t;
typedef struct ADC_16bits_tag {
int ADC_res;
uint16_t ADC_data;
} ADC_16bits_t;
ADC_16bits_t ADC_16bits;
ADC_8bits_t ADC_8bits;
void* ADC_value;
void Acquire_ADC(void* ADC_value);
void app_main(void)
{
ADC_16bits.ADC_res = 16;
ADC_16bits.ADC_data = 16000;
ADC_8bits.ADC_res = 8;
ADC_8bits.ADC_data = 250;
Acquire_ADC(&ADC_16bits);
Acquire_ADC(&ADC_8bits);
while(1)
{
vTaskDelay(100);
}
}
void Acquire_ADC(void* ADC_value)
{
if((*(ADC_16bits_t*)ADC_value).ADC_res == 16)
{
printf("This ADC has 16 bits of data %i\r\n", (*(ADC_16bits_t*)ADC_value).ADC_data);
} else {
if((*(ADC_8bits_t*)ADC_value).ADC_res == 8)
{
printf("This ADC has 8 bits of data %i\r\n", (*(ADC_8bits_t*)ADC_value).ADC_data);
}
}
}
This ADC has 16 bits of data 16000
This ADC has 8 bits of data 250