std::array 和 std::tuple 记忆顺序

std::array and std::tuple in memory order

我正在测试一个小代码片段,令我惊讶的是,与 std::array 和 std::tuple 中相同的 4 字节表示会产生不同的内存布局

#include <iostream>
#include <tuple>
#include <array>

struct XYZW {
  uint32_t x;
  uint32_t y;
  //std::array<uint8_t,4> z;
  std::tuple<uint8_t, uint8_t, uint8_t, uint8_t> z;
  uint32_t w;
};


int main() {
  XYZW i;
  i.z = {255, 0, 0, 0};
  uint32_t z = (*reinterpret_cast<uint32_t*>(&i.z));
  std::cout << z << " \n";
}

对于元组,输出为:4278190080,而对于数组,输出为:255。 这是预期的吗?

std::array 具有标准指定的布局,但 std::tuple 没有,并且可以是实现所需的任何内容。

所以预计它们 可能 不同,但当然它们也可能碰巧选择相同的布局,在某些 compilers/versions/platforms 上 - 只是不能保证。

实际上,实现 std::tuple 的最简单方法之一是递归,因为它最初是在 Loki 库中完成的。这将以相反的顺序布置字段(最基本的 class,其子对象排在第一位,是类型列表最后一个成员的叶)。但这不是唯一可能的实现,我观察到 compilers/standard 库实现之间的字段顺序不同。


注意。如评论中所述,您当前的诊断具有 UB - 但是,您可以安全地 hexdump reinterpret_cast<char*>(&i.z) 处的 4 个字节并获得等效结果。

std::array and std::tuple yield different in-memory layouts

Is this expected?

是的,这种可能性是可以预料的,尽管不能保证。

更具体地说,数组元素的内存顺序是低索引在低内存地址中。元组元素的存储顺序是未指定的。作为元组通常实现方式的副作用,逆向内存顺序是典型的。

uint32_t z = (*reinterpret_cast<uint32_t*>(&i.z));

这会导致未定义的行为。元组不是(保证是)标准布局类型,因此您不能将它们别名作为它们的第一个成员。