【问题标题】:How does padding of structs inside unions work?联合内部结构的填充如何工作?
【发布时间】:2018-05-08 08:35:38
【问题描述】:

我有以下:

#include <stdio.h>

typedef union u_data
{
        struct
        {
                int a;
                int b;
                int c;
        };
                int elem[3];
}       my_data;

int     main(void)
{
        my_data data;

        data.a = 3;
        data.b = 5;
        data.c = -3;
        printf("%d, %d, %d\n", data.elem[0], data.elem[1], data.elem[2]);
}

它按我预期的方式工作,输出:3, 5, -3

但是我知道结构中可以有填充,这是否意味着结构中的元素可能并不总是与数组对齐?

【问题讨论】:

  • 访问与最后一个写入的联合成员不同的成员会导致未定义的行为。所以:是的,在“可能是鼻恶魔”的意义上。
  • @Yunnosch 不,C 标准对联合有一个例外(排除可能的陷阱表示)。这里问的填充问题是不同的问题。
  • 作为我为什么问的一些背景信息......我最初看到stackoverflow.com/questions/8932707/…,第二条评论在做我正在做的事情
  • @user694733 我承认我可能错了。但是,您能否更详细地解释一下 gsamaras 赞成(和不反对)的答案,这似乎是一样的。有什么相关的区别?
  • @Yunnosch This recent answer 谈论工会成员的访问。到目前为止,这个问题只有大约 30 次观看,所以现在使用投票作为衡量正确性的指标还为时过早。

标签: c struct padding unions memory-alignment


【解决方案1】:

不能期望abc由于填充而与elem数组对齐,正如您正确指出的那样。

任何依赖于相反的代码都不是可移植的 C。

【讨论】:

    【解决方案2】:

    这是否意味着结构中的元素可能并不总是与数组对齐?

    没有

    您的代码调用未定义行为。

    数组elem 没有义务与结构的字段对齐(由于填充)。

    【讨论】:

    • 所有这些听起来都非常不正确。让我检查一下标准。
    • 好的,检查了标准,答案部分不正确。 “当您访问 a、b 和 c 时,您应该首先以某种方式初始化它们。”不正确,它不是 UB 而是实现定义的。“数组 elem 没有义务(由于填充)与结构。”是正确的。
    • 我最初确实同意你的观点(除了 abc 的事情),但你看到 user694733 和我之间的 cmets 线程了吗?似乎(令我惊讶)表明没有未定义的行为。有一个有趣的链接,stackoverflow.com/a/47430774/694733 我决定不尝试语言律师...
    【解决方案3】:

    可以在struct 的成员之间引入填充,以强制执行成员的个人对齐要求


    它按我的预期工作

    看起来在您的情况下,成员的对齐要求已经满足,因此没有引入填充,这导致数组完美映射struct

    这是否意味着结构中的元素可能并不总是对齐 用数组?

    不,因为struct 的成员之间可能会引入填充。

    【讨论】:

      【解决方案4】:
      • 首先,C、C11 6.5.2.3中联合有一个特殊的规则“公共初始序列”:

        一个特殊的保证是为了简化联合的使用:如果联合包含 几个结构共享一个共同的初始序列(见下文),如果联合 对象当前包含这些结构之一,允许检查常见的 它们中任何一个的初始部分,任何地方的完整类型的声明 可见。

        此规则不适用于此处,因为您的案例是一个结构和一个数组。如果是两个结构,规则就会适用。

      • 确实,结构可能具有填充,因此如果数组的对齐方式与结构不同,则无法保证获得正确的输出。这是实现定义的行为。

      • 考虑到这两种类型是兼容的,在 C(与 C++ 不同)C11 6.5.2.3/3 中写入结构和从数组读取都很好并且定义明确。只有在没有填充字节的情况下,结构才能与数组兼容。

      • “严格别名”不适用于此处。

      总结:这是实现定义的行为。如果编译器保证,您可以依赖特定系统上的特定行为。代码不可移植。

      【讨论】:

      • 答案的第一部分和最大部分解释一条不适用且未被询问的规则是否有用?
      • @EricPostpischil 是的,因为这里的其他人只是将“其未定义的行为”发布为下意识的反应。 C 中有很多情况允许类型双关语,指出这些很重要,因为 C++ 程序员往往会犯这个错误 - 在 C++ 中,许多情况会调用 UB。
      猜你喜欢
      • 2018-02-10
      • 1970-01-01
      • 1970-01-01
      • 2019-07-09
      • 2022-01-16
      • 1970-01-01
      • 2021-10-15
      • 2022-01-06
      • 2021-12-26
      相关资源
      最近更新 更多