Array of type void

arrayscvoid-pointers

plain C have nice feature – void type pointers, which can be used as pointer to any data type.
But, assume I have following struct:


struct token {
    int type;
    void *value;
};

where value field may point to char array, or to int, or something else.
So when allocating new instance of this struct, I need:

1) allocate memory for this struct;
2) allocate memory for value and assign it to value field.

My question is – is there ways to declare "array of type void", which can be casted to any another type like void pointer?

All I want is to use "flexible member array" (described in 6.7.2.1 of C99 standard) with ability to casting to any type.

Something like this:


struct token {
    int type;
    void value[];
};

struct token *p = malloc(sizeof(struct token) + value_size);
memcpy(p->value, val, value_size);
...
char *ptr = token->value;

I suppose declaring token->value as char or int array and casting to needed type later will do this work, but can be very confusing for someone who will read this code later.

Best Answer

Well, sort of, but it's probably not something you want:

struct token {
  // your fields
  size_t item_size;
  size_t length
};

struct token *make_token(/* your arguments */, size_t item_size, size_t length)
{
    struct token *t = malloc(sizeof *t + item_size * length);
    if(t == NULL) return NULL;
    t->item_size = item_size;
    t->length    = length;
    // rest of initialization
}

The following macro can be used to index your data (assuming x is a struct token *):

#define idx(x, i, t) *(t *)(i < x->length ? sizeof(t) == x->item_size ?
                       (void *)(((char *)x[1]) + x->item_size * i)
                     : NULL : NULL)

And, if you like, the following macro can wrap your make_token function to make it a little more intuitive (or more hackish, if you think about it that way):

#define make_token(/* args */, t, l) (make_token)(/* args */, sizeof(t), l)

Usage:

struct token *p = make_token(/* args */, int, 5); // allocates space for 5 ints
...
idx(p, 2, int) = 10;