138

Is it possible to dereference a void pointer without type-casting in the C programming language?

Also, is there any way of generalizing a function which can receive a pointer and store it in a void pointer and by using that void pointer, can we make a generalized function?

for e.g.:

void abc(void *a, int b)
{
   if(b==1)
      printf("%d",*(int*)a);     // If integer pointer is received
   else if(b==2)
      printf("%c",*(char*)a);     // If character pointer is received
   else if(b==3)
      printf("%f",*(float*)a);     // If float pointer is received
}

I want to make this function generic without using if-else statements - is this possible?

Also if there are good internet articles which explain the concept of a void pointer, then it would be beneficial if you could provide the URLs.

Also, is pointer arithmetic with void pointers possible?

pdoherty926
  • 9,895
  • 4
  • 37
  • 68
AGeek
  • 5,165
  • 16
  • 56
  • 72
  • For some, this may read better if the * is attached to the 'type' rather than the name. I.e. that `a` is a pointer to some void (memory hole). Hence, in each print statement, we tell the compiler what sort of 'hole/void' we it is expected `a` to point to, and then we get that sort of value from that pointer. (falls out of researching some size_t issues on LLP32/LP64 difficulties;-) – Philip Oakley Aug 08 '21 at 12:18

16 Answers16

101

Is it possible to dereference the void pointer without type-casting in C programming language...

No, void indicates the absence of type, it is not something you can dereference or assign to.

is there is any way of generalizing a function which can receive pointer and store it in void pointer and by using that void pointer we can make a generalized function..

You cannot just dereference it in a portable way, as it may not be properly aligned. It may be an issue on some architectures like ARM, where pointer to a data type must be aligned at boundary of the size of data type (e.g. pointer to 32-bit integer must be aligned at 4-byte boundary to be dereferenced).

For example, reading uint16_t from void*:

/* may receive wrong value if ptr is not 2-byte aligned */
uint16_t value = *(uint16_t*)ptr;
/* portable way of reading a little-endian value */
uint16_t value = *(uint8_t*)ptr
                | ((*((uint8_t*)ptr+1))<<8);

Also, is pointer arithmetic with void pointers possible...

Pointer arithmetic is not possible on pointers of void due to lack of concrete value underneath the pointer and hence the size.

void* p = ...
void *p2 = p + 1; /* what exactly is the size of void?? */
user694733
  • 15,208
  • 2
  • 42
  • 68
Alex B
  • 82,554
  • 44
  • 203
  • 280
  • 3
    Unless I recall incorrectly, you can safely dereference a void* in two ways. Casting to char* is always acceptable, and if you know the original type it points to you can cast to that type. The void* has lost the type info so it'd have to be stored elsewhere. – Dan Olson Mar 29 '09 at 10:30
  • 1
    Yes, you can always dereference if you cast into another type, but you can't do the same if you *don't* cast. In short, the compiler won't know what assembly instructions to use for math operations *until* you cast it. – Zachary Hamm Mar 29 '09 at 15:12
  • 20
    I think GCC treats arithmetic on `void *` pointers the same as `char *`, but it's not standard and you shouldn't rely on it. – ephemient Mar 30 '09 at 17:40
  • if ptr is void* type before casting it to (uint8_t)*, when you do ***ptr+1***, how many bytes is it skipping? is it by default skipping 1 byte like char*? Thank you – Cong Hui Oct 27 '13 at 18:53
  • 1
    Could you give some links that if (void *) points to valid uint16_t value, we can't dereference by *(uint16_t *) ptr? This is what I see first in my life, that dereferencing is not portable. – likern Jan 25 '14 at 16:44
  • 1
    @likern You certainly *can* deference it and the compiler will assume it's properly aligned. The problem is, it's not guaranteed to be, because you could have passed an unaligned pointer elsewhere in the code (if it's cast to `void*`, the compiler won't complain). – Alex B Jan 26 '14 at 00:39
  • 5
    I'm not sure I follow. In example that OP listed above the incoming types are guaranteed to be correct by the user of the function. Are you saying that if we have something where we assign a value of known type to a pointer, cast it to a void pointer and then cast it back to the original pointer type that it could become unaligned? I don't understand why the compiler would undermine you like that just randomly unaligning things simply because you cast them to a void pointer. Or are you simply saying that we can't trust the user to know the type of arguments that they passed to the function? – doliver Nov 14 '14 at 23:28
  • 1
    @doliver: i have similar doubt as you do in above comment- is this issue resolved to you now? – Giorgi Moniava Apr 19 '15 at 16:25
  • 2
    @doliver I meant #2 ("we can't trust the user to know the type of arguments that they passed to the function"). But revisiting my answer from 6 years ago (ugh, has it really been that long?) I can see what you mean, it's not *always* the case: when the original pointer pointed to the proper type, it would be already aligned, so it'd be safe to cast without alignment issues. – Alex B Apr 19 '15 at 16:37
  • 1
    • A pointer to void will have the same representation and memory alignment as a pointer to char. I read this in the book understanding and using c pointers by richard reese pg-14, and if this is correct then I think pointer arithmetic should be possible in it. – Pranjal Kumar Sep 16 '17 at 21:34
33

In C, a void * can be converted to a pointer to an object of a different type without an explicit cast:

void abc(void *a, int b)
{
    int *test = a;
    /* ... */

This doesn't help with writing your function in a more generic way, though.

You can't dereference a void * with converting it to a different pointer type as dereferencing a pointer is obtaining the value of the pointed-to object. A naked void is not a valid type so derefencing a void * is not possible.

Pointer arithmetic is about changing pointer values by multiples of the sizeof the pointed-to objects. Again, because void is not a true type, sizeof(void) has no meaning so pointer arithmetic is not valid on void *. (Some implementations allow it, using the equivalent pointer arithmetic for char *.)

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • 1
    @CharlesBailey In your code, you write `void abc(void *a, int b)`. But why not use `void abc(int *a, int b)`, since in your function you eventually will define `int *test = a;`, it would save one variable, and I don't see any other advantages by defining another variable. I see many codes writen in this way using `void *` as parameters, and casting variables later in the function. But since this funtion is written by author, so he must know the usage of the variable, therefore, why use `void *`? Thanks – Lion Lai Oct 27 '17 at 07:01
  • I believe what you wanted to say is "You can't dereference a `void *` *without* converting it to a different pointer type" – oeter Feb 17 '22 at 15:40
17

You should be aware that in C, unlike Java or C#, there is absolutely no possibility to successfully "guess" the type of object a void* pointer points at. Something similar to getClass() simply doesn't exist, since this information is nowhere to be found. For that reason, the kind of "generic" you are looking for always comes with explicit metainformation, like the int b in your example or the format string in the printf family of functions.

Chris Tang
  • 567
  • 7
  • 18
Erich Kitzmueller
  • 36,381
  • 5
  • 80
  • 102
7

So far my understating on void pointer is as follows.

When a pointer variable is declared using keyword void – it becomes a general purpose pointer variable. Address of any variable of any data type (char, int, float etc.)can be assigned to a void pointer variable.

main()
{
    int *p;

    void *vp;

    vp=p;
} 

Since other data type pointer can be assigned to void pointer, so I used it in absolut_value(code shown below) function. To make a general function.

I tried to write a simple C code which takes integer or float as a an argument and tries to make it +ve, if negative. I wrote the following code,

#include<stdio.h>

void absolute_value ( void *j) // works if used float, obviously it must work but thats not my interest here.
{
    if ( *j < 0 )
        *j = *j * (-1);

}

int main()
{
    int i = 40;
    float f = -40;
    printf("print intiger i = %d \n",i);
    printf("print float f = %f \n",f);
    absolute_value(&i);
    absolute_value(&f);
    printf("print intiger i = %d \n",i);
    printf("print float f = %f \n",f);
    return 0;
}   

But I was getting error, so I came to know my understanding with void pointer is not correct :(. So now I will move towards to collect points why is that so.

The things that i need to understand more on void pointers is that.

We need to typecast the void pointer variable to dereference it. This is because a void pointer has no data type associated with it. There is no way the compiler can know (or guess?) what type of data is pointed to by the void pointer. So to take the data pointed to by a void pointer we typecast it with the correct type of the data holded inside the void pointers location.

void main()

{

    int a=10;

    float b=35.75;

    void *ptr; // Declaring a void pointer

    ptr=&a; // Assigning address of integer to void pointer.

    printf("The value of integer variable is= %d",*( (int*) ptr) );// (int*)ptr - is used for type casting. Where as *((int*)ptr) dereferences the typecasted void pointer variable.

    ptr=&b; // Assigning address of float to void pointer.

    printf("The value of float variable is= %f",*( (float*) ptr) );

}

A void pointer can be really useful if the programmer is not sure about the data type of data inputted by the end user. In such a case the programmer can use a void pointer to point to the location of the unknown data type. The program can be set in such a way to ask the user to inform the type of data and type casting can be performed according to the information inputted by the user. A code snippet is given below.

void funct(void *a, int z)
{
    if(z==1)
    printf("%d",*(int*)a); // If user inputs 1, then he means the data is an integer and type casting is done accordingly.
    else if(z==2)
    printf("%c",*(char*)a); // Typecasting for character pointer.
    else if(z==3)
    printf("%f",*(float*)a); // Typecasting for float pointer
}

Another important point you should keep in mind about void pointers is that – pointer arithmetic can not be performed in a void pointer.

void *ptr;

int a;

ptr=&a;

ptr++; // This statement is invalid and will result in an error because 'ptr' is a void pointer variable.

So now I understood what was my mistake. I am correcting the same.

References :

http://www.antoarts.com/void-pointers-in-c/

http://www.circuitstoday.com/void-pointers-in-c.

The New code is as shown below.


#include<stdio.h>
#define INT 1
#define FLOAT 2

void absolute_value ( void *j, int *n)
{
    if ( *n == INT) {
        if ( *((int*)j) < 0 )
            *((int*)j) = *((int*)j) * (-1);
    }
    if ( *n == FLOAT ) {
        if ( *((float*)j) < 0 )
            *((float*)j) = *((float*)j) * (-1);
    }
}


int main()
{
    int i = 0,n=0;
    float f = 0;
    printf("Press 1 to enter integer or 2 got float then enter the value to get absolute value\n");
    scanf("%d",&n);
    printf("\n");
    if( n == 1) {
        scanf("%d",&i);
        printf("value entered before absolute function exec = %d \n",i);
        absolute_value(&i,&n);
        printf("value entered after absolute function exec = %d \n",i);
    }
    if( n == 2) {
        scanf("%f",&f);
        printf("value entered before absolute function exec = %f \n",f);
        absolute_value(&f,&n);
        printf("value entered after absolute function exec = %f \n",f);
    }
    else
    printf("unknown entry try again\n");
    return 0;
}   

Thank you,

André Alves
  • 6,535
  • 3
  • 17
  • 23
Megharaj
  • 1,589
  • 2
  • 20
  • 32
7

A void pointer is known as generic pointer, which can refer to variables of any data type.

Zach Johnson
  • 23,678
  • 6
  • 69
  • 86
Sneha
  • 71
  • 1
  • 1
2

Here is a brief pointer on void pointers: https://www.learncpp.com/cpp-tutorial/613-void-pointers/

6.13 — Void pointers

Because the void pointer does not know what type of object it is pointing to, it cannot be dereferenced directly! Rather, the void pointer must first be explicitly cast to another pointer type before it is dereferenced.

If a void pointer doesn't know what it's pointing to, how do we know what to cast it to? Ultimately, that is up to you to keep track of.

Void pointer miscellany

It is not possible to do pointer arithmetic on a void pointer. This is because pointer arithmetic requires the pointer to know what size object it is pointing to, so it can increment or decrement the pointer appropriately.

Assuming the machine's memory is byte-addressable and does not require aligned accesses, the most generic and atomic (closest to the machine level representation) way of interpreting a void* is as a pointer-to-a-byte, uint8_t*. Casting a void* to a uint8_t* would allow you to, for example, print out the first 1/2/4/8/however-many-you-desire bytes starting at that address, but you can't do much else.

uint8_t* byte_p = (uint8_t*)p;
for (uint8_t* i = byte_p; i < byte_p + 8; i++) {
  printf("%x ",*i);
}
Community
  • 1
  • 1
2

No, it is not possible. What type should the dereferenced value have?

zvrba
  • 24,186
  • 3
  • 55
  • 65
2
void abc(void *a, int b) {
  char *format[] = {"%d", "%c", "%f"};
  printf(format[b-1], a);
}
  • Is this program possible.... Please do check, if this possible in C programming... – AGeek Mar 30 '09 at 03:09
  • 2
    Yes, this is possible (although the code is dangerous without a range check for b). Printf takes a variable number of arguments and a is just pushed on the stack as any pointer (without any type information) and popped inside the printf function using va_arg macros using info from the format string. – hlovdal Apr 15 '09 at 15:12
  • @SiegeX: please describe what is not portable, and what may be undefined. – Gauthier Oct 31 '11 at 09:13
  • @Gauthier passing a variable which contains format specifiers is not portable and potentially undefined behavior. If you want to do something like that then look at the 'vs' flavor of `printf`. [This answer](http://stackoverflow.com/questions/1056411/how-to-pass-variable-number-of-arguments-to-printf-sprintf) has a good example for that. – SiegeX Nov 01 '11 at 17:54
  • In practice, I would probably replace `int b` with an enum, but making any later change to that enum would break this function. – Jack Stout May 20 '14 at 17:26
  • This guarantees undefined behaviour by usong an incorrect format specifier (only `%p` can apply to `void *`) – M.M May 16 '19 at 00:22
1

Void pointers are pointers that has no data type associated with it.A void pointer can hold address of any type and can be typcasted to any type. But, void pointer cannot be directly be dereferenced.

int x = 1;
void *p1;
p1 = &x;
cout << *p1 << endl; // this will give error
cout << (int *)(*p) << endl; // this is valid
1

I want to make this function generic, without using ifs; is it possible?

The only simple way I see is to use overloading .. which is not available in C programming langage AFAIK.

Did you consider the C++ programming langage for your programm ? Or is there any constraint that forbids its use?

yves Baumes
  • 8,836
  • 7
  • 45
  • 74
  • Ok, that's a shame . From my point of view I see no solutions then. Actually, it is the same as printf() & cout : 2 different ways to implement printing. printf() use if() statement to decode the format string(I suppose or something similar), while for cout case operator << is an overloaded function – yves Baumes Mar 30 '09 at 08:22
0

You can easily print a void printer

int p=15;
void *q;
q=&p;
printf("%d",*((int*)q));
Ankit Bansal
  • 2,162
  • 8
  • 42
  • 79
0

Because C is statically-typed, strongly-typed language, you must decide type of variable before compile. When you try to emulate generics in C, you'll end up attempt to rewrite C++ again, so it would be better to use C++ instead.

0

void pointer is a generic pointer.. Address of any datatype of any variable can be assigned to a void pointer.

int a = 10;
float b = 3.14;
void *ptr;
ptr = &a;
printf( "data is %d " , *((int *)ptr)); 
//(int *)ptr used for typecasting dereferencing as int
ptr = &b;
printf( "data is %f " , *((float *)ptr));
//(float *)ptr used for typecasting dereferencing as float
0

You cannot dereference a pointer without specifying its type because different data types will have different sizes in memory i.e. an int being 4 bytes, a char being 1 byte.

gotoat
  • 31
  • 6
-1

Fundamentally, in C, "types" are a way to interpret bytes in memory. For example, what the following code

struct Point {
  int x;
  int y;
};

int main() {
  struct Point p;
  p.x = 0;
  p.y = 0;
}

Says "When I run main, I want to allocate 4 (size of integer) + 4 (size of integer) = 8 (total bytes) of memory. When I write '.x' as a lvalue on a value with the type label Point at compile time, retrieve data from the pointer's memory location plus four bytes. Give the return value the compile-time label "int.""

Inside the computer at runtime, your "Point" structure looks like this:

00000000 00000000 00000000 00000000 00000000 00000000 00000000

And here's what your void* data type might look like: (assuming a 32-bit computer)

10001010 11111001 00010010 11000101
noɥʇʎԀʎzɐɹƆ
  • 9,967
  • 2
  • 50
  • 67
-2

This won't work, yet void * can help a lot in defining generic pointer to functions and passing it as an argument to another function (similar to callback in Java) or define it a structure similar to oop.

Rand0m
  • 342
  • 1
  • 4
  • 10