Reputation: 85
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
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
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
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