【问题标题】:Casting structure pointer to union pointer将结构指针转换为联合指针
【发布时间】:2016-10-09 23:19:12
【问题描述】:

我有一个union 包含各种兼容的struct 成员:

enum Type { T1, T2, … };

struct S1 { enum Type type; … };
struct S2 { enum Type type; … };
…

union U {
    enum Type type;
    struct S1 as_s1;
    struct S2 as_s2;
    …
};

这些结构的type字段被视为不可变的,只有当前type对应的union的字段被访问。我知道只要 type 不变量得到支持,就定义了将 union U * 转换为 struct S1 *,但反过来也是如此吗?

struct S1 *s1 = malloc (sizeof (struct S1));
union U *u = (union U *)s1;

也就是说,只分配sizeof (struct S1) 字节并将结果转换为union U * 是否安全?我想避免分配 sizeof (union U) 字节,在我的情况下可能会大得多。

【问题讨论】:

  • 为什么会有type 工会成员?将类型放入一个包装对象泛型包装器中以实现多态性。
  • @self:这是 C,不是 C++。只是一个标准的标记联合。
  • 没错。你不需要 C++ 来做我在评论中描述的事情。将其转换为 union 很好,因为 sizeof(your_union) 将是 union 所有成员的最大大小。您一次只能访问工会的一名成员
  • @self:我知道我可以转换值,我只是想知道是否还定义了指针转换,因为联合可以更严格地对齐,并且允许 @987654334 似乎很奇怪@ 实际上不能被取消引用——在上面的例子中,*u 肯定是非法的。
  • @self:我猜你的意思是struct Wrapper { enum Type type; union { struct S1 as_s1; … } data; };?这也有同样的问题。

标签: c struct casting undefined-behavior unions


【解决方案1】:

演员表本身不太可能成为问题。只要 struct 和 union 类型具有相同的对齐要求,它们就被允许。此外,在这种情况下,标准要求如果将值转换回原始类型,则结果应与原始指针进行比较,因此不会丢失任何数据。

问题是当您访问指向的对象时会发生什么,就好像它是union U。您可以这样做的某些事情可能会很好,但其他事情肯定是不安全的。具体来说,你问

也就是说,只分配 sizeof (struct S1) 字节并将结果强制转换为 union U * 是否安全?

不,这不安全。该标准规定:

当一个值存储在结构或联合类型的对象中时,包括在成员对象中,对应于任何填充字节的对象表示的字节采用未指定的值。 [...]

当一个值存储在联合类型对象的成员中时,对象表示中与该成员不对应但与其他成员对应的字节采用未指定的值。

(C2011,6.2.6/6-7)

如果您触发其中一项规定,尤其是后者,并且分配的空间没有联合的表示那么大,那么程序会表现出未定义的行为。有可能您可以避免这样做的程序操作,但在我的书中,对程序行为创建此类额外约束不能被描述为“安全”。

我想避免分配 sizeof (union U) 字节,在我的情况下可能会大得多。

既然您显然打算使用工会的type 成员来确定要使用哪个成员,那么这样做如何:

struct generic_s {
    enum Type type;
    void *contents;
};

struct generic_s s = { T1 };
s.contents = malloc(sizeof (struct S1));

直接传递struct_generic 类型的对象以避免额外的分配和释放:

do_something(s);  // i.e. not do_something(&s)

当然,您需要强制转换 contents 指针以取消引用它。另一方面,这只是对指针进行一些花哨的包装以识别指向的类型。相反,您可以不进行包装并显式传递类型信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-21
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2015-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多