plain C有很好的功能 - void类型指针,它可以用作指向任何数据类型的指针 但是,假设我有以下结构:
struct token {
int type;
void *value;
};
其中value字段可以指向char数组,或指向int或其他内容 所以在分配这个结构的新实例时,我需要:
1)为这个结构分配内存;
2)为值分配内存并将其分配给值字段。
我的问题是 - 是否有办法声明“数组类型为void”,它可以被转换为任何其他类型,如void指针?
我想要的只是使用“灵活的成员阵列”(在C99标准的6.7.2.1中描述),能够投射到任何类型。
这样的事情:
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;
我认为将token->值声明为char或int数组,并且稍后转换为所需类型将执行此工作,但对于稍后将阅读此代码的人来说可能会非常混乱。
答案 0 :(得分:4)
嗯,有点,但可能不是你想要的东西:
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
}
以下宏可用于索引数据(假设x
为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)
并且,如果您愿意,以下宏可以包装您的make_token
函数以使其更直观(或者如果您按照这种方式考虑,则更加hackish):
#define make_token(/* args */, t, l) (make_token)(/* args */, sizeof(t), l)
用法:
struct token *p = make_token(/* args */, int, 5); // allocates space for 5 ints
...
idx(p, 2, int) = 10;
答案 1 :(得分:1)
我可能会这样做:
struct token {
int type;
void *value;
};
struct token p;
p.value = malloc(value_size);
p.value[0] = something;
p.value[1] = something;
...
编辑,实际上你必须对那些p.value [index] = somethings进行类型转换。和/或使用联合而不必进行类型转换。
答案 2 :(得分:1)
你不能有一个'void'项目数组,但你应该能够做你想要的事情,只要你在做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; }
请注意,如果您想获得额外的存储空间,则需要额外的地址运算符。
type *ptr = (type*)&(token->value);
这将“浪费”sizeof(void *)字节,value
的原始类型并不重要,因此您也可以使用较小的项目。我可能typedef char placeholder;
并将value
打字。
答案 3 :(得分:1)
扩展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;
}
注意使用&#34; offsetof()&#34;而不是&#34; sizeof()&#34;在分配内存时,为了避免浪费&#34; void * buf;&#34;字段大小。 &#34; buf&#34;的类型并不重要,但使用&#34; void *&#34;意味着它会调整&#34; buf&#34;结构中的字段最适合指针,如果需要,在它之前添加填充。这通常为条目提供更好的内存对齐,特别是如果它们至少与指针一样大。
访问缓冲区中的条目如下所示;
/** Get a pointer to the i'th entry. */
void *buffer_get(buffer_t *t, int i)
{
return &t->buf + i * t->size;
}
注意额外的地址 - 运营商以获取&#34; buf&#34;的地址。 field作为分配的条目存储器的起始点。
答案 4 :(得分:0)
以下结构可以帮助您。
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;
}
更多详情:clibutils
答案 5 :(得分:0)
类型void的数组在c/c++中不支持。 例如:
int main() {
void alexa[]; // error: declaration of ‘alexa’ as array of void
return 0;
}
void 指针 数组在 c/c++ 中受支持。 下面的例子:
int main(int argc, char argv*[])
{
void *alexa[100]; // Compiled successfully
return 0;
}