void 类型的数组

发布于 2024-11-03 07:30:09 字数 692 浏览 0 评论 0原文

普通 C 有一个很好的功能 - void 类型指针,它可以用作任何数据类型的指针。
但是,假设我有以下结构:


struct token {
    int type;
    void *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->value 声明为 char或 int 数组并稍后转换为所需类型将完成这项工作,但对于稍后阅读此代码的人来说可能会非常困惑。

plain C have nice feature - void type pointers, which can be used as pointer to any data type.
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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

開玄 2024-11-10 07:30:09

好吧,有点像,但这可能不是您想要的:

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 函数,使其更直观(或者更黑客,如果你这样想的话):

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

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;
此生挚爱伱 2024-11-10 07:30:09

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

注意分配内存时使用“offsetof()”而不是“sizeof()”,以避免浪费“void *buf;”字段大小。 “buf”的类型并不重要,但使用“void *”意味着它将针对指针最佳地对齐结构中的“buf”字段,如果需要,可以在其前面添加填充。这通常可以为条目提供更好的内存对齐,特别是当它们至少与指针一样大时。

访问缓冲区中的条目如下所示;

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

请注意额外的寻址运算符,用于获取“buf”字段的地址作为分配的条目内存的起点。

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.

伪心 2024-11-10 07:30:09

我可能会这样做:

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] = somes 进行类型转换。和/或使用联合来不必进行类型转换。

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.

阳光的暖冬 2024-11-10 07:30:09

你不能有一个“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 设置为该类型。

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.

执笔绘流年 2024-11-10 07:30:09

以下结构可以帮助您。

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

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

你是年少的欢喜 2024-11-10 07:30:09

c/c++ 中支持void类型的数组。
示例如下:

int main() {

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

return 0;

}

c/c++ 支持void 指针数组。
下面的例子:

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

void *alexa[100]; // Compiled successfully

return 0;

}

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;

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文