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 child1struct 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;
}