【问题标题】:Is there any standard for where data is located in a C union?数据在 C 联合中的位置是否有任何标准?
【发布时间】:2015-10-27 15:42:00
【问题描述】:

我有以下工会:

union problem {
    int i;
    int *v;
};

在我的系统上,int 是 4 个字节,而 int* 是 8 个字节。我有一个由 10 个这样的结构组成的数组。在某段代码中,我碰巧知道数组的所有成员都在使用联合的int。我需要将这些整数复制到一个整数数组中。现在,如果源数组是一个 int 数组,我可以使用 memcpy 快速复制数据。

是否可以保证 int 存储在联合的低内存或高内存中?我希望能够在不迭代的情况下复制数据,所以我正在考虑使用 SIMD 和随机播放进行循环。要做到这一点,我必须知道 int 在联合中的实际位置,我猜这是特定于实现的。

【问题讨论】:

  • 不,C 规范不保证。这是一个联合,这意味着成员 i 和成员 v 都从相同的内存位置开始。 problem 的总大小将取决于任何联合成员的最大大小加上完成的任何填充。 memcpy() 有它的用途,但这不是其中之一。最好遍历数组并分配每个数组。还做一个memcpy() 也在内存区域上进行迭代。
  • 我很好奇,当数组只有 10 个左右的元素并且一个简单的循环可以解决问题并且您可以移动时,为什么要优化联合数组的特定成员的复制做别的事。
  • @RichardChambers:关于成员存储在联合的表示中的 where 有保证,而不是 int 和指针的位如何对应价值。
  • @RichardChambers 10 只是一个例子,因为讨论起来并不重要。但实际上它是一系列长度在 20 到 200 之间的 100-20000 个数组。可能值得返回并重写结构以避免联合并向其他结构添加更多字段。工会的选择是一个早期的设计决定,以减少逻辑或其他东西(当时这似乎是合理的)。现在看来是不明智的。
  • @R.. 我看不出你写的和我写的有什么区别。一般规则是你知道它们从哪里开始,然后你真正可以指望的是为联合分配的任何内存区域,无论是在堆栈上还是在堆上,或者任何地方都足够大以包含任何特定的成员工会。我看到很多错误是由于人们假设他们可以依靠特定的对齐方式,尤其是在涉及未明确指定成员对齐方式的结构的联合中。

标签: c arrays simd unions


【解决方案1】:

联合的两个元素都与它们的第一个字节一起存储在联合的起始地址。在您的示例中,intint * 都存储在同一地址开始。这始终是有保证的。

未定义的是int 是存储在int * 的较低有效字节还是较高有效字节上。请注意,如果您有一个联合数组,则将元素全部复制到 int 的数组中会将不确定的值复制到目标数组的每个备用成员中(实际上;理论上这可能是严格未定义的行为)。

因此,要从包含十个 union problem 的数组中复制十个 int 值,您需要遍历数组的元素,依次复制 .i 成员。

union problem p[10] = { … };
int copy[10];

要么:

for (int i = 0; i < 10; i++)
    copy[i] = p[i].i;

或者:

int *cp = copy;
union problem *pp = p;
int *end = copy + 10;
while (cp < end)
    *cp++ = (*pp++).i;

【讨论】:

  • 所以在有效复制方面我不太可能比foo.i上的循环做得更好?
  • 正确;你不太可能比循环复制做得更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-02
  • 2021-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-13
  • 2016-11-18
相关资源
最近更新 更多