将结构指针转换为联合指针
Casting structure pointer to union pointer
我有一个 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)
字节,在我的情况下这可能要大得多。
演员表本身不太可能成为问题。只要结构和联合类型具有相同的对齐要求,它们就被允许。此外,在那种情况下,标准要求如果将值转换回原始类型,则结果应与原始指针比较,因此不会丢失任何数据。
问题是当您访问 指向的对象时会发生什么,就好像它是union U
。您可以这样做的某些事情很可能会很好地解决问题,但其他事情肯定是不安全的。具体来说,你问
That is, is it safe to allocate only sizeof (struct S1) bytes and cast the result to union U *?
不,这不安全。标准规定:
When a value is stored in an object of structure or union type, including in a member object, the bytes of the object representation that correspond to any padding bytes take unspecified values. [...]
When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values.
(C2011, 6.2.6/6-7)
如果您触发了这些规定之一,尤其是后者,并且分配的 space 没有联合的代表那么大,那么程序会表现出未定义的行为。您可能可以避免这样做的程序操作,但是在我的书中不能将对程序行为创建这样的额外约束描述为 "safe"。
I would like to avoid allocating sizeof (union U) bytes, which in my case may be significantly larger.
由于您显然打算使用联盟的 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
指针以取消引用它。另一方面,这只是对指针进行一些花哨的包装以识别所指向的类型。相反,您可以不使用包装并显式传递类型信息。
我有一个 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)
字节,在我的情况下这可能要大得多。
演员表本身不太可能成为问题。只要结构和联合类型具有相同的对齐要求,它们就被允许。此外,在那种情况下,标准要求如果将值转换回原始类型,则结果应与原始指针比较,因此不会丢失任何数据。
问题是当您访问 指向的对象时会发生什么,就好像它是union U
。您可以这样做的某些事情很可能会很好地解决问题,但其他事情肯定是不安全的。具体来说,你问
That is, is it safe to allocate only sizeof (struct S1) bytes and cast the result to union U *?
不,这不安全。标准规定:
When a value is stored in an object of structure or union type, including in a member object, the bytes of the object representation that correspond to any padding bytes take unspecified values. [...]
When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values.
(C2011, 6.2.6/6-7)
如果您触发了这些规定之一,尤其是后者,并且分配的 space 没有联合的代表那么大,那么程序会表现出未定义的行为。您可能可以避免这样做的程序操作,但是在我的书中不能将对程序行为创建这样的额外约束描述为 "safe"。
I would like to avoid allocating sizeof (union U) bytes, which in my case may be significantly larger.
由于您显然打算使用联盟的 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
指针以取消引用它。另一方面,这只是对指针进行一些花哨的包装以识别所指向的类型。相反,您可以不使用包装并显式传递类型信息。