C语言 void 类型的数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5783770/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
array of type void
提问by S.J.
plain C have nice feature - void type pointers, which can be used as pointer to any data type.
But, assume I have following struct:
普通 C 有一个很好的特性——void 类型指针,它可以用作指向任何数据类型的指针。
但是,假设我有以下结构:
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:
其中 value 字段可能指向 char 数组、int 或其他内容。
因此,在分配此结构的新实例时,我需要:
1) allocate memory for this struct;
2) allocate memory for value and assign it to value field.
1) 为这个结构分配内存;
2)为值分配内存并将其分配给值字段。
My question is - is there ways to declare "arrayof type void", which can be casted to any another type like void pointer?
我的问题是 - 有没有办法声明“ void 类型的数组”,它可以转换为任何其他类型,如 void 指针?
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.
我想要的只是使用能够转换为任何类型的“灵活成员数组”(在 C99 标准的 6.7.2.1 中描述)。
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.
我想将 token->value 声明为 char 或 int 数组并稍后转换为所需的类型将完成这项工作,但对于稍后阅读此代码的人来说可能会非常混乱。
回答by Chris Lutz
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 xis a struct token *):
以下宏可用于索引您的数据(假设x是 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_tokenfunction to make it a little more intuitive (or more hackish, if you think about it that way):
而且,如果您愿意,以下宏可以包装您的make_token函数,使其更直观(或者更黑客,如果您这样想的话):
#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;
回答by AShelly
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.
您不能拥有“空”项目的数组,但只要您在执行 malloc 时知道 value_size,您就应该能够做您想做的事情。但它不会漂亮。
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.
请注意,当您想要获得额外的存储空间时,您需要一个额外的 address-of 运算符。
type *ptr = (type*)&(token->value);
This will 'waste' sizeof(void*) bytes, and the original type of valuedoesn't really matter, so you may as well use a smaller item. I'd probably typedef char placeholder;and make valuethat type.
这将“浪费” sizeof(void*) 字节,并且原始类型value并不重要,因此您最好使用较小的项目。我可能会typedef char placeholder;做value那种类型的。
回答by old_timer
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.
编辑,实际上你必须对那些 p.value[index] = 东西进行类型转换。和/或使用联合来不必进行类型转换。
回答by Donovan Baarda
Expanding on AShelly's answer you can do this;
扩展 AShelly 的答案,您可以这样做;
/** 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.
注意在分配内存时使用“offsetof()”而不是“sizeof()”以避免浪费“void *buf;” 场大小。“buf”的类型无关紧要,但使用“void *”意味着它将最佳地对齐结构中的“buf”字段以用于指针,如果需要,在它之前添加填充。这通常为条目提供更好的内存对齐,特别是如果它们至少与指针一样大。
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.
请注意额外的 address-of 运算符,用于获取“buf”字段的地址作为分配的入口内存的起点。
回答by Avinash
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
更多细节:clibutils

