doubleshot
doubleshot

Reputation: 85

Casting a void pointer to an arbitrary type pointer

I am attempting to do my own implementation of common data structures in C for my own learning benefit. My current effort is a vector, and I want it to be able to hold a single arbitrary type (or at least type size, but isn't that all that really matters in C?). My struct is as follows:

struct vector
{
    void *item;
    size_t element_size;
    size_t num_elements;
}

However, what I don't understand is how I can refer to specific elements in the *item array if the type is supposed to be arbitrary. I know the element_size, but that doesn't help me with index referencing (e.g. item[5]) because void is not a type. I figured it would be easiest to refer to the elements as byte offsets. So if I was holding a vector of structs with size 12, item[5] would be at 12*5=60 bytes from item*. However, I don't understand how to retrieve that data. I know I want 12 bytes from item+60, but how would I make the compiler understand that? Am I getting into preprocessor territory?

Upvotes: 1

Views: 3259

Answers (3)

Steve Jessop
Steve Jessop

Reputation: 279215

sizeof is measure in chars, so you can do this:

void *start_of_sixth_element = ((char*)item) + (5 * element_size);

Someone who knows what the type of each element is could then cast start_of_sixth_element to the correct type to use it.

void* is a bad choice in a way, since you can't do pointer arithmetic with void* pointers in standard C (there's a GNU extension to allow it, but for portable code you use char* or unsigned char* at least for the arithmetic).

Code that knows the correct type before applying the offset 5, could just do this:

correct_type *sixth_element = ((correct_type *)item) + 5;

void is not a type

It is a type, it's just not a "complete type". "Incomplete type" pretty much means the compiler doesn't know what a void* really points to.

Upvotes: 2

Seki
Seki

Reputation: 11465

So if I was holding a vector of structs with size 12, item[5] would be at 12*5=60 bytes from item*. However, I don't understand how to retrieve that data. I know I want 12 bytes from item+60, but how would I make the compiler understand that?

Say that your given type is foo. As you already understood, you need to reach the address at item + (5 * 12) then dereference the void pointer after casting it to foo*.

foo my_stuff = *(foo *)(item + 5 * 12);

You can also use sizeof() if you can determine at compile time the type of your data :

foo my_stuff = *(foo *)(item + 5 * sizeof(foo));

Upvotes: 0

ouah
ouah

Reputation: 145829

The void * is a generic pointer type for any object pointer type. You have to know what type it points into in order to correctly cast the void * and dereference the pointer.

Here is an example with a void * object used with different pointer types.

void *p;
int a = 42, b;
double f = 3.14159, g;

p = &a;
b = *(int *) a;

p = &f;
g = *(double *) f; 

Upvotes: 0

Related Questions