开发者

array of type void

plain C have nice feature - void type pointers, which can be used as pointer to any data ty开发者_Python百科pe.

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.


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;


Expanding on AShelly's answer you can do this;

/** A buffer structure containing count entries of the given size. */
typedef struct {
    size_t size;
    int count;
    void *buf;
} buffer_t;

/** Allocate a new buffer_t with "count" entries of "size" size. */
buffer_t *buffer_new(size_t size, int count)
{
    buffer_t *p = malloc(offsetof(buffer_t, buf) + count*size);
    if (p) {
        p->size = size;
        p->count = count;
    }
    return p;
}

Note the use of "offsetof()" instead of "sizeof()" when allocating the memory to avoid wasting the "void *buf;" field size. The type of "buf" doesn't matter much, but using "void *" means it will align the "buf" field in the struct optimally for a pointer, adding padding before it if required. This usually gives better memory alignment for the entries, particularly if they are at least as big as a pointer.

Accessing the entries in the buffer looks like this;

/** Get a pointer to the i'th entry. */
void *buffer_get(buffer_t *t, int i)
{
    return &t->buf + i * t->size;
}

Note the extra address-of operator to get the address of the "buf" field as the starting point for the allocated entry memory.


I would probably do this:

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

struct token p;

p.value = malloc(value_size);

p.value[0] = something;
p.value[1] = something;
...

edit, actually you have to typecast those p.value[index] = somethings. And/or use a union to not have to typecast.


You can't have an array of 'void' items, but you should be able to do something like what you want, as long as you know value_size when you do the malloc. But it won't be pretty.

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

value_size = sizeof(type)*item_count;
struct token *p = malloc(sizeof(struct token) + value_size);
//can't do memcpy:  memcpy(p->value, val, value_size);  
//do this instead
type* p = (type*)&(p->value);
type* end = p+item_count;
while (p<end) { *p++ = someItem; }

Note that you need an extra address-of operator when you want to get the extra storage.

type *ptr = (type*)&(token->value); 

This will 'waste' sizeof(void*) bytes, and the original type of value doesn't really matter, so you may as well use a smaller item. I'd probably typedef char placeholder; and make value that type.


following structure can help you.

struct clib_object_t {
void* raw_data;
size_t size;
};

struct clib_object_t*
new_clib_object(void *inObject, size_t obj_size) {
    struct clib_object_t* tmp = (struct clib_object_t*)malloc(sizeof(struct clib_object_t));   
    if ( ! tmp )
        return (struct clib_object_t*)0;
    tmp->size        = obj_size;
    tmp->raw_data    = (void*)malloc(obj_size);
    if ( !tmp->raw_data ) {
        free ( tmp );
        return (struct clib_object_t*)0;
    }
    memcpy ( tmp->raw_data, inObject, obj_size);
    return tmp;
}

clib_error
get_raw_clib_object ( struct clib_object_t *inObject, void**elem) {
    *elem = (void*)malloc(inObject->size);
    if ( ! *elem )
        return CLIB_ELEMENT_RETURN_ERROR;
    memcpy ( *elem, inObject->raw_data, inObject->size );

    return CLIB_ERROR_SUCCESS;
}

More Details : clibutils


Array of type void is not supporting in c/c++. Example like:

int main() {

 void  alexa[]; // error: declaration of ‘alexa’ as array of void 

return 0;

}

Array of void pointer is supported in c/c++. Example below:

int main(int argc, char argv*[]) 
{

void *alexa[100]; // Compiled successfully

return 0;

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜