【问题标题】:Calculating malloc size of a tagged union (without over-allocating)计算标记联合的 malloc 大小(不过度分配)
【发布时间】:2021-01-14 03:30:48
【问题描述】:

假设我有以下结构:

typedef struct MyObject {
    char* tag;
    union {
        BigObject b;     // imagine this is 5MB
        SmallObject s;   // imagine this is 8 bytes
    } u;
}

来自标准(复制自this answer):

...联合的大小足以包含其最大的数据成员。每个数据成员的分配就像它是结构的唯一成员一样。

有没有办法让特定结构的确切大小达到malloc?类似于tag* (8) + padding (?) + [small or big object size] (?)。换句话说,考虑到正确的union-ed 对象大小,我怎样才能得到相当于MyObject o; sizeof(o) 的值?

【问题讨论】:

  • 这有XY 问题的味道。如果您解释您要解决的问题会更好,因为这是错误的方法。
  • @dxiv 这是一个概念性问题。这就是为什么我让一个成员5MB......
  • 你可以照你说的做——使用sizeof(MyObject)
  • @M.M 当我只需要这么多字节时,我只想分配 16 个字节——当然,这是一个概念性问题,我只是想看看这种类型的东西在 C 中是否可行不可能。
  • @samuelbrody1249 这里的概念是您不能以任何安全或可移植的方式“切片”这样的结构。如果你想在 C 中模拟继承,还有其他不使用标记联合的方法。

标签: c union


【解决方案1】:

为结构分配内存时,您必须为整个结构提供足够的空间,即使您只使用包含联合的较小成员。

如果您没有分配足够的内存并且您要写入更大的成员,您将调用undefined behavior 来写入过去分配的内存。即使您只写信给较小的成员,也不能保证您不会遇到问题。

例如,如果您这样做:

MyObject *o1, *o2;
o1 = malloc(sizeof(char *) + sizeof(SmallObject)); 
o2 = malloc(sizeof(char *) + sizeof(SmallObject)); 
o1->tag = "small";
// assign values in o1.u.s
*o2 = *o1;

最后一行的赋值会触发未定义的行为,因为 整个 结构会被复制。

当前定义结构的方式,最好只分配 sizeof(struct MyObject) 字节并完成它。

作为替代方案,您可以使用指向包含结构的指针并分别为它们分配空间。

typedef struct MyObject {
    char* tag;
    union {
        BigObject *b;
        SmallObject* s;
    } u;
} MyObject;

...
MyObject *o = malloc(sizeof(MyObject));
o->tag = "big";
o->u.b = malloc(sizeof(BigObject));

【讨论】:

  • 对,这是我手动处理各种结构成员并且从不交叉转换、强制转换的情况。等
  • 另一种方法是在同一联合中的数组末尾使用flexible array member。当然必须分配内存以包含足够的当前存储的对象
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-31
  • 2018-02-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-27
  • 2014-08-01
相关资源
最近更新 更多