Array of type void

plain C has a nice feature - pointers of type void, which can be used as a pointer to any data type.
But suppose I have the following structure:

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

where the value field may point to a char array or to int or something else.
Therefore, when distributing a new instance of this structure, I need:

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

My question is: are there any ways to declare an " array of type void" that can be passed to any other type, like a void pointer?

All I want is to use a “flexible array of elements” (described in 6.7.2.1 of the C99 standard) with the ability to cast for any type.

Something like that:

 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 assume that declaring token-> value as a char or int array and casting to the desired type will later do the job, but it can be very confusing for those who read this code later.

+6
source share
5 answers

Well, sort of, but this is probably not what 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 want, the following macro can wrap your make_token function to make it more intuitive (or more hacky if you think so):

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

Using:

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

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, in fact you need to output those p.value [index] = somethings. And / or use a union so that it does not have a type.

+1
source

You cannot have an array of "void" elements, but you should be able to do something like what you want, as long as you know value_size when you do malloc. But that will not be so.

 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; } 

Please note that you need an additional operator address if you want to get additional storage.

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

This will “lose” sizeof (void *) bytes, and the original type value does not matter, so you can use a smaller element. I would probably typedef char placeholder; and made a value that will print.

+1
source

The 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; } 

Read more: clibutils

0
source

Turning to AShelly's answer, you can do it;

 /** 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 memory to avoid losing "void * buf;" field size. The type “buf” does not really matter, but using “void *” means that it aligns the “buf” field in the structure optimally for the pointer, adding padding to it if necessary. This usually gives better memory alignment for records, especially if they are no less than a pointer.

Access to the entries in the buffer is as follows:

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

Pay attention to the additional address of the operator to get the address of the "buf" field as the starting point for the allocated input memory.

0
source

Source: https://habr.com/ru/post/886658/


All Articles