Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use a void pointer for dereferencing variables of datatypes?

Dereferencing a float variable using a void pointer:

#include <stdio.h>

int main() {
    float a = 7.5;
    void *vp = &a;
    printf("%f", *(float*)vp); /* Typecasting a void pointer to float for dereference */
    printf("\n");
}

Output: 7.500000

Dereferencing a variable using an integer pointer:

#include <stdio.h>

int main() {
    float a = 7.5;
    int *ip = &a;
    printf("%f", *(float*)ip); /* Typecasting an int pointer to float for dereference */
    printf("\n");
}

Output: 7.500000

In both, the outputs are same. What is the reason to go for dereferencing of different datatype variable, when we are able to do by typecasting a normal pointer?

like image 962
Jaivvignesh Avatar asked Aug 25 '17 05:08

Jaivvignesh


People also ask

What is one reason you would use a void pointer?

Why do we use a void pointer in C programs? We use the void pointers to overcome the issue of assigning separate values to different data types in a program. The pointer to void can be used in generic functions in C because it is capable of pointing to any data type.

Why is type casting used to access the value of any variable using a void pointer?

Why we use void pointers? We use void pointers because of its reusability. Void pointers can store the object of any type, and we can retrieve the object of any type by using the indirection operator with proper typecasting.

What is a void pointer can you dereference a void pointer without knowing its type?

You cannot. Dereferencing a void pointer requires an explicit cast beforehand. You can ofcourse cast it to any particular type and then dereference it without knowing its original type, but why you would want to do that is beyond me.

Why we Cannot dereference a void pointer?

The compiler will not let you dereference a void* pointer because it does not know the size of the object pointed to.


3 Answers

Converting any data pointer to void* pointer and back is guaranteed to give back original pointer.

From C11 standard draft N1570:

6.3.2.3 Pointers

  1. A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

Converting data pointer to other data pointer than void* (int* in your example) may work. It depends on the compiler you are using and the system you are on. Not all systems might use same internal representation for different pointer types.

  1. A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned 68) for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.

This is different from strict aliasing rules.

float a = 7.5;    
int *ip=&a;
int i = *ip; // Dereferenced using invalid type

Code above breaks strict aliasing rule as dereferenced type is not the same as the original type. This results in undefined behaviour and is always invalid code.

like image 159
user694733 Avatar answered Oct 07 '22 13:10

user694733


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.

like image 25
msc Avatar answered Oct 07 '22 12:10

msc


A void pointer is (sort of) untyped. It can point to anything without the compiler complaining. e.g. If you have an int variable, you can safely create a void pointer that points to this and pass it around. e.g.

int x = 10;
void *p = &x 

is fine but

int x = 10;
float *p = &x; 

will upset the compiler

This is especially useful for functions that operate on multiple pointer types or if you will decide what something is at runtime.

However, void pointers cannot be dereferenced (*) directly because the compiler doesn't know their type. So,

printf("%d\n", *p); 

will break if p is void pointer. We have to know the size of what it points to to dereference it and this is done using a manual type cast (like what you've done).

In your specific case, you have a pointer that points to a float which you type cast back into float before printing it. So, you will get the same output. The void * pointer is not really playing a big role here.

An example of where you need a void * is the malloc function, If you look at the prototype, it returns a void *. i.e. a block of raw memory. You need to typecast this as a concrete type before you can do pointer arithmetic and dereferencing.

like image 4
Noufal Ibrahim Avatar answered Oct 07 '22 12:10

Noufal Ibrahim