为什么使用reinterpret_cast 将char* 转换为结构似乎可以正常工作?

Why does using reinterpret_cast to convert from char* to a structure seem to work normally?

人们说相信 reinterpret_cast 从原始数据(如 char*)转换为结构是不好的。例如,对于结构

struct A
{
    unsigned int a;
    unsigned int b;
    unsigned char c;
    unsigned int d;
};

sizeof(A) = 16__alignof(A) = 4,完全符合预期。

假设我这样做:

char *data = new char[sizeof(A) + 1];
A *ptr = reinterpret_cast<A*>(data + 1); // +1 is to ensure it doesn't points to 4-byte aligned data

然后复制一些数据到ptr:

memcpy_s(sh, sizeof(A),
         "\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00", sizeof(A));

ptr->a为1,ptr->b为2,ptr->c为3,ptr->d为4。
好吧,似乎工作。正是我所期待的。

但是 ptr 指向的数据不是像 A 那样的 4 字节对齐。这可能会在 x86 或 x64 平台中导致什么问题?性能问题?

一方面,您的初始化字符串假定基础整数以小端格式存储。但是另一种体系结构可能使用大端,在这种情况下,您的字符串将产生垃圾。 (一些巨大的数字。)该架构的正确字符串是

"\x00\x00\x00\x01\x00\x00\x00\x02\x03\x00\x00\x00\x00\x00\x00\x04".

当然还有对齐的问题。

某些架构甚至不允许您将 data + 1 的地址分配给非字符指针,它们会发出 内存对齐陷阱 .

但即使是允许这样做的架构(如 x86)也会表现得很糟糕,必须为结构中的每个整数执行两次内存访问。 (有关更多信息,请参阅这个出色的答案: )

最后,我对此并不完全确定,但我认为 C 和 C++ 甚至不能向您保证字符数组将包含以字节为单位的字符。 (我希望了解更多的人可以澄清这一点。)可以想象,可能存在完全无法处理非字对齐数据的体系结构,因此在此类体系结构中,每个字符都必须占据整个字。这意味着获取 data + 1 的地址是有效的,因为它仍然是对齐的,但是您的初始化字符串不适合预期的工作,因为它的前 4 个字符将覆盖您的整个结构, 产生 a=1, b=0, c=0 和 d=0.

问题是您无法确定此代码是否会 运行 在另一个平台上,下一个版本 Visual Studio 等。当 运行 在另一个处理器上运行时,可能会导致硬件异常。

曾几何时,您可以读取任意内存位置,但如今所有这些程序都因 "access violation" 异常而崩溃。该程序将来可能会发生类似的事情。

但是,您可以做什么,以及任何自称 "C++ standard compliant" 的编译器必须正确编译的是:
你可以 reinterpret_cast 指向其他东西的指针,然后返回到原来的类型。类型的值在前后读取时必须保持相同。

我不知道你到底想做什么,但是你可能逃脱,例如

  • 分配一个struct A
  • reinterpret_cast将其转换为 chars
  • 将内存内容保存到文件

稍后恢复所有内容:

  • 分配一个struct A
  • reinterpret_castchars
  • 加载内容到内存
  • reinterpret_cast它回一个struct A