gpt4 book ai didi

c - 使用灵活数组成员时正确的 malloc 大小

转载 作者:行者123 更新时间:2023-11-30 20:24:54 25 4
gpt4 key购买 nike

我试图弄清楚当我使用灵活的数组成员时需要分配多少空间。我有以下内容

typedef struct _A
{
struct other;
MyStruct params[1];
} A;

typedef struct _B
{
int size;
unsigned char values[1];
} B;

typedef struct _MyStruct
{
int one;
int two;
int three;
} MyStruct;

我想要做什么:填写 MyStruct,创建一个结构体 B,并将它们都添加到结构体 A 中。

所以我有以下内容:

MyStruct test;
test.one = 1;
test.two = 2;
test.three 3;

unsigned char *input = (unsigned char *) malloc(arraysize);

//fill up input with data...then
B *testB = malloc(sizeof(*testB) + arraysize);
testB->size = arraysize;
//put input into the structure
memcpy(testB->values, input, arraysize);

//Here I want to add both test, and testB to a struct A - what do I need to do here?

A *testA = malloc(SOME SIZE HERE?)
testA->other=NULL;
testA->params[0]= ????
testA->params[1]=???

是的,我知道我想要添加到参数中的两个结构并不相同,但我将在稍后对它们进行转换。

最佳答案

这行不通。为什么?因为A有固定的布局:

sizeof(other)
sizeof(MyParams)
sizeof(MyParams)
...

MyParams 插槽中可以容纳的内容不能大于 MyParams。因此,一般来说,可变大小的 B 不适合那里。您还存在对齐问题:如果您紧接着一个又一个地追加项目,那么您就忽略了平台上的对齐要求。因此,没有填充对齐的简单附加将不起作用。

您似乎确实希望 A 成为任意大小的对象的集合。在最通用的方式中,您可以简单地存储通用(void*)指针的数组:

typedef struct {
Other other;
void ** params;
} A;

然后您可以将“任何内容”放入params中:

void test(void) {
A a;
a.params = (void**)malloc(sizeof(void*) * 3);
a.params[0] = malloc(sizeof(MyStruct));
((MyStruct*)a.params[0])->one = 1;
...
a.params[1] = malloc(sizeof(B) + arraysize);
((A*)a.params[1])->size = arraysize;
...
a.params[2] = NULL; // you have to somehow indicate the last item
}

要取消分配,请迭代 params 直到获得 null 元素:

void destroyA(A * a) {
void ** p;
for (p = a->params; *p; ++p) free(*p);
free(a->params);
}

唉,您不知道每个 params 指针中实际存储的内容 - 因此很难安全地使用它们。

为了更加安全,您应该有一个可区分(标记)的 union 来表示“通用”元素。

enum AnyTag { BTag = 0, MyParamsTag = 1 };

typedef struct {
...
} B;

typedef struct {
...
} MyParams;

typedef struct {
AnyTag tag;
B d;
} TaggedB;

typedef struct {
AnyTag tag;
MyParams d;
} TaggedMyParams;

typedef union {
AnyTag tag;
TaggedB b;
TaggedMyParams myParams;
} Any;

typedef struct {
Other other;
Any ** params;
} A;

这样就可以更轻松地确保您正确访问成员:

void destroyA(A * a) {
Any ** p;
for (p = a->params; *p; ++p) free(*p);
free(a->params);
}

void test(void) {
A a;
a.params = (Any**)malloc(sizeof(AnyTag*) * 3);

a.params[0] = (Any*)malloc(sizeof(TaggedMyParams));
a.params[0]->myParams.tag = MyParamsTag;
a.params[0]->myParams.d.one = 1;
...
a.params[1] = (Any*)malloc(sizeof(TaggedB) + arraysize);
a.params[1]->b.tag = BTag;
a.params[1]->b.d.size = arraysize;
memcpy(a.params[1]->b.d.values, input, arraysize);
...
a.params[2] = NULL;
...
process(&a);
}

void processMyParams(MyParams *);
void processB(B *);
void process(A * a) {
Any ** param = a->params;
for (Any ** param = a->params; *param; ++param) {
switch(param->tag) {
case MyParamsTag:
process(&param->myParams.d);
break;
case BTag:
process(&param->b.d);
break;
}
}
}

如果您愿意将标签放入基本类型 BMyParams 本身,则 trick shown here您可以去掉 d 以便更容易输入:

enum AnyTag { BTag = 0, MyParamsTag = 1 };

typedef struct {
AnyTag tag;
...
} B;

typedef struct {
AnyTag tag;
...
} MyParams;

typedef union {
AnyTag tag;
B b;
MyParams myParams;
} Any;

typedef struct {
Other other;
Any ** params;
} A;

还有:

void test(void) {
A a;
a.params = (Any**)malloc(sizeof(AnyTag*) * 3);

a.params[0] = (Any*)malloc(sizeof(TaggedMyParams));
a.params[0]->myParams.tag = MyParamsTag;
a.params[0]->myParams.one = 1;
...
a.params[1] = (Any*)malloc(sizeof(TaggedB) + arraysize);
a.params[1]->b.tag = BTag;
a.params[1]->b.size = arraysize;
memcpy(a.params[1]->b.values, input, arraysize);
...
a.params[2] = NULL;
...
process(&a);
}

关于c - 使用灵活数组成员时正确的 malloc 大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32015864/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com