联合体中是否存在填充。

11

大家好,
我想知道联合(union)是否使用填充(padding)?
由于联合体的大小等于最大数据成员的大小,所以最后是否可能存在填充?


1
简而言之,是的!在我的Windows系统上,联合体被填充为大小是int大小的倍数,即4个字节。因此,除非您使用#pragma pack(1),否则大小为3个字节的联合体将填充一个额外的字节以产生4个字节。在发布问题之前,请编写一个程序并尝试一下。 - Rüppell's Vulture
一个联合体被填充以具有 int 的大小的倍数,即 4 字节。但在这种情况下, union ab{ char a; }a; 大小为 1。 - akash
1
在您的情况下根本没有填充。谁说padding总是会被执行?就像Daniel Fischer所说,这并不是标准要求的。 - Rüppell's Vulture
这个联合体在我的Windows系统上占用4个字节,除非我使用#pragma pack(1),那么它将占用3个字节。 - Rüppell's Vulture
2个回答

16

由于联合体的大小是最大数据成员的大小

这并不一定正确。考虑以下例子:

union Pad {
    char arr[sizeof (double) + 1];
    double d;
};
那个联合体中最大的成员是arr。但通常情况下,double会在四个或八个字节的倍数上对齐(取决于架构和double的大小)。在某些架构上,这甚至是必要的,因为它们不支持未对齐读取。
所以sizeof (union Pad)通常比sizeof (double) + 1更大[在64位系统上,通常为16 = 2 * sizeof (double),在32位系统上可能为16或12(在具有8位char和64位double的32位系统上,double所需的对齐方式仍可能只有四个字节)]。
这意味着联合体中必须存在填充,并且只能放置在末尾。
通常,union的大小将是不小于最大成员的任何要求的最大对齐方式的最小倍数。

但是当我们在联合中只有char arr[sizeof(double)+1]时,它只会给出大小:9? - Dineshkumar
这并不是标准规定的,实现可以添加填充,但通常情况下(使用8字节的双精度浮点数),是的,这将给出大小为9。 - Daniel Fischer
有人成功展示了这个例子会填充吗?我问这个问题是因为我不认为在这里填充有任何理由,好像两个成员之间需要有空间一样,它应该只选择最大的一个。 - ideasman42
1
@ideasman42,您可以编写并运行一个小程序来打印出doubleunion Pad的大小,以检查编译器是否插入了填充。在64位系统上,我从gcc和clang中都得到了联合体大小是double大小的两倍(16 = 2 * 8),这是预期的结果。填充的原因是对齐(双方都将double对齐到8字节边界)。 - Daniel Fischer
有趣的是,它确实对齐了,但是如果将 double d 替换为 char d[sizeof(double)],则联合体不会填充。(至少在linux/gcc下) - ideasman42
@ideasman42 是的,因为char的对齐方式是1。如果你使用int d[2],你可能会得到12作为大小,因为现在int通常是四个字节,并且有四个字节的对齐方式。(除了在嵌入式系统上,它可能经常是两个字节。) - Daniel Fischer

-2

当我们在其中使用原始类型时,Union

union
{
    char c;
    int x;
}

看起来它没有使用填充,因为最大尺寸的数据总是对齐到边界。

但是当我们在联合体中嵌套结构时,它会使用填充。

    union u
    {
        struct ss
        {
            char s;
            int v;
        }xx;
    }xu;

这导致大小为8。

所以你的问题的答案是UNION中存在PADDING。


1
正如Daniel所建议的,这是错误的。你把结构体的填充当作联合体的填充,这是误导性的。 - kadina

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