将足够的内存分配给联合体中的一个成员是否有问题?

3

能否分配足够容纳特定联合成员的内存?我的意思是这样的:

#include <stdio.h>
#include <string.h>
#include <malloc.h>

union u;

union u{
    int a;
    long b[4096];
};

int main(){
    union u tmp = {.a = 42};
    union u *u = (union u*) malloc(sizeof(int)); //not malloc(sizeof(union u))
    memcpy(u, &tmp, sizeof(int));
    printf("u::a = %lu\n", u -> a);
}

sizeof(union u) 等于 sizeof(long[4096]),为了只容纳一个 int,分配 4096 * sizeof(long) 的内存会浪费空间。

像上面那样做是可能的吗?还是未定义行为?


2
我有一种感觉,联合并不是你想要的。你实际的问题是什么? - Nelfeal
2
一个 union 需要完整的大小 (即在你的情况下 sizeof(union u))。其他任何内容都是无效的。 - Some programmer dude
2
@Someprogrammerdude 有参考资料吗? - Some Name
3
因为union只能同时包含一个成员。 标准规定:具有联合类型的对象一次只能包含一个成员。那么将联合对象设置为包含int a并且只分配足以容纳此int a的内存有什么问题? - Some Name
2
memcpy(u, &tmp, sizeof(int)); is conceptually amiss. memcpy(&u->a, &tmp.a, sizeof u->a); makes more sense - or just u->a = tmp.a; - chux - Reinstate Monica
显示剩余5条评论
2个回答

2
我找到了为什么使用union是无效的答案。根据N1570::6.2.5p(20):“联合类型描述了一个重叠的非空成员对象集合,每个成员对象都有可选择的名称和可能不同的类型。”
这意味着,联合对象必须分配足够的内存来容纳联合的每个成员,但是它们是重叠的。在我的情况下,这是不合法的union用法,因为我只分配了足够容纳其中一个成员的内存。

不同意。在代码示例中,union *u 从未被使用,只有成员 u -> a 被使用。当然,tmp = *u; 是无效的。只要使用具有分配内存的成员,我认为没有问题。关于 union 的规则适用于指针 u 在作为联合体解除引用之后。u -> a 只是一个 int - chux - Reinstate Monica
@chux 现在我真的很困惑...那么我在问题中提供的代码示例是有效的吗?我认为它不是因为没有分配足够的存储空间,所以 u 指向的对象根据我提供的定义并不是真正的联合。 - Some Name
对象u是指针类型,而不是联合类型。 u->a是一个int。确实,*u无效,因为那里没有足够的内存,但代码不使用*u。只要代码不使用*u,你看到了什么问题?“由u指向的对象”不适用,因为代码从未完全取消引用u。(关于此问题您使用哪个编译器?) - chux - Reinstate Monica
@chux u->a 使用 *u:它是基于 *u 定义的。 - curiousguy

1

是否可以分配足够容纳特定联合成员的内存?

是的。但代码不能尝试使用未分配的部分中的成员。


为了清晰起见,下文使用union ab而不是union u

代码的初始部分没有问题。

#include <stdio.h>
#include <string.h>
#include <malloc.h>

union ab;

union ab {
    int a;
    long b[4096];
};

int main(){
    union ab tmp = {.a = 42};

将指针分配给稀疏内存本身并不是问题。虽然不需要强制转换,但我发现为对象/成员分配大小比为类型分配大小更具信息量(更易编码、审查和维护)。
    // union ab *u = (union ab*) malloc(sizeof(int)); //not malloc(sizeof(union ab))
    union ab *u = malloc(sizeof u->a);

复制/赋值没有问题,因为u指向的内存足够。
    memcpy(u, &tmp, sizeof(int));
    // or 
    u.a = tmp.a;

打印输出存在问题,因为代码使用了不匹配的说明符。在已更正的代码中,访问成员.a没有问题。
    // printf("ab::a = %lu\n", u -> a);
    printf("ab::a = %d\n", u->a);

到目前为止没有问题。

某些新代码存在问题,因为代码试图通过u读取分配内存之外的数据 - 这是未定义行为(UB)。

    temp = *u;
}

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