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));
这会导致未定义的行为。元组不是(保证是)标准布局类型,因此您不能将它们别名作为它们的第一个成员。
我正在测试一个小代码片段,令我惊讶的是,与 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));
这会导致未定义的行为。元组不是(保证是)标准布局类型,因此您不能将它们别名作为它们的第一个成员。