C 在不知道其类型的情况下动态分配和初始化结构
C Dynamically Allocate and Initialize Struct Without Knowing Its Type
我有一系列结构,它们都有一些相对冗长的初始化逻辑,我正在尝试将其重构为辅助函数,这样我就不必一遍又一遍地编写它。这是一个浓缩版:
struct base
{
const int *i;
}
struct child1
{
struct base b;
int j;
}
struct child2
{
struct base b;
int k;
}
void *alloc_base_holder(const int *i, size_t size)
{
struct base b = { i };
void *anon = malloc(size);
// error GD320D622: 'memcpy' forming offset [N1, N2] is out of the bounds [0, N3] of object 'b' with type 'struct base'
return memcpy(anon, &b, size);
}
struct child1 *c1_alloc(const int *i)
{
return (struct child1 *)alloc_base_holder(i, sizeof(struct child1));
}
struct child2 *c2_alloc(const int *i)
{
return (struct child2 *)alloc_base_holder(i, sizeof(struct child2));
}
我正在尝试根据结构的大小而不是类型动态分配和初始化内存,但我不确定该怎么做。
我的第一个想法是初始化所有 child
类型共有的 base
部分,然后 memcpy
将其初始化为 void
指针已分配给正确的 size
,但出现错误:
error GD320D622: 'memcpy' forming offset [N1, N2] is out of the bounds [0, N3] of object 'b' with type 'struct base'
我也有过手动设置 void
指针 (anon
) 的内存的想法,但如果可能的话,我还没有想出正确的搜索词来查找它。
这可能吗?有人能给我指出正确的方向吗?
编辑:
顺便说一下,我在 C99 中使用 gcc。
您得到“错误”是因为您从 base
结构 b
复制了 size
个字节,即使 size > sizeof b
(这将超出b
结构对象)。
我建议您改用 calloc
,让分配器零初始化分配的内存。
然后只复制 base
结构本身,即 sizeof b
而不是:
memcpy(anon, &b, sizeof b);
当然,你首先要确定 size >= sizeof b
.
您可以只为 base
的实例分配 size
个字节。
struct base *b = malloc(size);
然后照常初始化成员。
警告的原因在其他答案中解释。
我建议始终通过对象的最终类型(struct child1
或 struct child2
)访问对象。否则,由于严格的别名规则,很容易触发 UB。
因此最好有 init_base_holder()
而不是 alloc_base_holder
.
void init_base_holder(struct base *b, const int *i)
{
b->i = i;
}
struct child1 *c1_alloc(const int *i)
{
struct child1 *c = malloc(sizeof *c);
init_base_holder(&c->b, i);
return c;
}
struct child2 *c2_alloc(const int *i)
{
struct child2 *c = malloc(sizeof *c);
init_base_holder(&c->b, i);
return c;
}
我有一系列结构,它们都有一些相对冗长的初始化逻辑,我正在尝试将其重构为辅助函数,这样我就不必一遍又一遍地编写它。这是一个浓缩版:
struct base
{
const int *i;
}
struct child1
{
struct base b;
int j;
}
struct child2
{
struct base b;
int k;
}
void *alloc_base_holder(const int *i, size_t size)
{
struct base b = { i };
void *anon = malloc(size);
// error GD320D622: 'memcpy' forming offset [N1, N2] is out of the bounds [0, N3] of object 'b' with type 'struct base'
return memcpy(anon, &b, size);
}
struct child1 *c1_alloc(const int *i)
{
return (struct child1 *)alloc_base_holder(i, sizeof(struct child1));
}
struct child2 *c2_alloc(const int *i)
{
return (struct child2 *)alloc_base_holder(i, sizeof(struct child2));
}
我正在尝试根据结构的大小而不是类型动态分配和初始化内存,但我不确定该怎么做。
我的第一个想法是初始化所有 child
类型共有的 base
部分,然后 memcpy
将其初始化为 void
指针已分配给正确的 size
,但出现错误:
error GD320D622: 'memcpy' forming offset [N1, N2] is out of the bounds [0, N3] of object 'b' with type 'struct base'
我也有过手动设置 void
指针 (anon
) 的内存的想法,但如果可能的话,我还没有想出正确的搜索词来查找它。
这可能吗?有人能给我指出正确的方向吗?
编辑: 顺便说一下,我在 C99 中使用 gcc。
您得到“错误”是因为您从 base
结构 b
复制了 size
个字节,即使 size > sizeof b
(这将超出b
结构对象)。
我建议您改用 calloc
,让分配器零初始化分配的内存。
然后只复制 base
结构本身,即 sizeof b
而不是:
memcpy(anon, &b, sizeof b);
当然,你首先要确定 size >= sizeof b
.
您可以只为 base
的实例分配 size
个字节。
struct base *b = malloc(size);
然后照常初始化成员。
警告的原因在其他答案中解释。
我建议始终通过对象的最终类型(struct child1
或 struct child2
)访问对象。否则,由于严格的别名规则,很容易触发 UB。
因此最好有 init_base_holder()
而不是 alloc_base_holder
.
void init_base_holder(struct base *b, const int *i)
{
b->i = i;
}
struct child1 *c1_alloc(const int *i)
{
struct child1 *c = malloc(sizeof *c);
init_base_holder(&c->b, i);
return c;
}
struct child2 *c2_alloc(const int *i)
{
struct child2 *c = malloc(sizeof *c);
init_base_holder(&c->b, i);
return c;
}