为联合体分配内存,以及联合体指针与指向联合体的指针数组之间的区别。

3

因为我的问题(链接)没有得到明确的答案,所以我再次提问希望有人知道:

  1. 指向联合体和包含其元素指针的联合体之间除了语法上的区别之外,是否存在任何区别?在示例中生成的汇编代码相同。
  2. 只要我从未访问其他成员,就可以仅为其中一个成员(不是最大的成员)分配内存,这样做是否允许?

关于第二个问题,C89草案的第6.5.2.1节如下:

联合体的大小足以容纳其成员中最大的一个——联合体对象最多可以存储一个成员的值。适当转换为联合体对象的指针可以指向其每个成员(或者如果一个成员是位域,则指向它所在的单元),反之亦然。

因此,至少在正确转换时,仅为一个成员分配空间应该是可以的,但我找不到任何保证只使用所访问成员对应的位的内容的内容。

编辑:

给定以下定义:

typedef struct s1
{
    int a;
} s1;

typedef struct s2
{
    int a;
    int b;
} s2;

union u1
{
    s1 a;
    s2 b;
};

这合法吗:
union u1 *u = malloc(sizeof(s1));
u->a.a = 3;
printf("s1.a=%d\n", u->a.a);
printf("s2.a=%d\n", u->b.a);

除了语法上的区别,指向联合体的指针和包含指向其元素的指针的联合体之间有什么区别吗?是的,后者没有意义。联合体不能包含指向其元素的指针,因为该指针将成为元素本身。这有点像说“我想建造我的房子,同时我希望我的房子成为指向我的房子的路标”。所以我对这个问题毫无头绪——你试图解决的实际问题是什么? - Lundin
为什么您想要仅为较小的成员分配足够的空间?如果是这样,那么联合体可能并不是您要寻找的对象。只需分配一个较小结构的实例即可。其次,考虑到联合体的典型用例,我认为成员指向其他成员的指针是有风险的。也就是说,除非每个“顶级”对象在相同位置具有指针,但仍然存在风险...。 - Andrew Falanga
@AndrewFalanga 我上一个问题的答案是使用联合体。如果我为两者分配了足够的空间,那么单向链表将变得非常无用。 - Kona98
马克:标准不允许您分配比联合的最大成员需要的空间更少的空间。您可能能够摆脱它,但这将不是完全符合规范的代码。联合体(像结构体一样,不像数组)可以用作单个对象,因此 union Funion a, *b; b = malloc(sizeof Small); a.small.field1 = 1; *b = a; 将会溢出内存。您可以争辩说您永远不会那样做,并且逐字段复制“a”将起作用;可能会,但据我所知,标准并不保证它。 - rici
@rici 如果我有一个联合体,其中包含两个指向不同结构体的指针,它们共享一个公共的初始序列,那该怎么办?我为它们中的任何一个分配空间,并且只访问公共成员。或者通过另一个与分配的结构体不同的结构体访问成员是否会导致未定义行为?这里是我的意思的一个例子。 - Kona98
显示剩余4条评论
1个回答

2
我认为你对指向联合体的事情存在误解。
使用你提供的示例代码的一部分(这部分代码应该包括在问题主体中)。
union u1
{
    s1 a;
    s2 b;
};

然后如果你有
union u1 my_union;

我保证&my_union等于&my_union.a&my_union.b


关于

union u1 *u = malloc(sizeof(s1));
u->a.a = 3;
printf("s1.a=%d\n", u->a.a);
printf("s2.a=%d\n", u->b.a);

这仅有两个原因才能实现:使用联合体允许类型转换,且 u->a.au->b.a 的大小和位置完全相同。我认为在技术上来说这是未定义行为,但由于其他要求而起作用。
如果您尝试访问 u->b.b,则将保证出现未定义行为。

很抱歉,我不明白这个回答如何解决我的问题。此外,这似乎与“适当转换为联合对象指针”的部分不一致,这表明&my_union需要转换为s1或s2才能正常工作。 - Kona98
1
@MarcSchulze 强制类型转换 就是 “合适的转换” 。在第一部分中,我只是说地址保证相等,这就是为什么转换(强制类型转换)保证能够工作的原因。 - Some programmer dude

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接