void类型的数组

时间:2011-04-25 22:04:01

标签: c arrays void-pointers

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数组,并且稍后转换为所需类型将执行此工作,但对于稍后将阅读此代码的人来说可能会非常混乱。

6 个答案:

答案 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
}

以下宏可用于索引数据(假设xstruct 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;

}