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

C++ 为什么使用reinterpret_cast将char*转换为结构似乎可以正常工作?,c++,struct,reinterpret-cast,C++,Struct,Reinterpret Cast,人们说,将原始数据(如char*)转换为结构时,信任reinterpret\u cast是不好的。例如,对于结构 struct A { unsigned int a; unsigned int b; unsigned char c; unsigned int d; }; sizeof(A)=16和\u alignof(A)=4,与预期完全一致 假设我这样做: char *data = new char[sizeof(A) + 1]; A *ptr = reint

人们说,将原始数据(如
char*
)转换为结构时,信任
reinterpret\u cast
是不好的。例如,对于结构

struct A
{
    unsigned int a;
    unsigned int b;
    unsigned char c;
    unsigned int d;
};
sizeof(A)=16
\u 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->a
是1,
ptr->b
是2,
ptr->c
是3,
ptr->d
是4。
好的,似乎有用。正是我所期待的


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

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

“\x00\x00\x00\x01\x00\x00\x00\x00\x02\x03\x00\x00\x00\x00\x00\x00\x00\x04”

当然,还有对齐的问题

某些体系结构甚至不允许将数据+1的地址分配给非字符指针,它们将发出内存对齐陷阱

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


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

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

曾经有一段时间,你可以读取任意的内存位置,但现在所有这些程序都会因“访问冲突”异常而崩溃。类似的事情将来可能会发生在这个项目上

但是,您能做的,以及任何自称“符合C++标准”的编译器必须正确编译的是:
您可以
重新解释\u cast
指向其他对象的指针,然后返回原始类型。在前后读取时,类型的值必须保持不变

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

  • 分配
    结构a
  • 重新解释\u cast
    将其转换为
    char
    s
  • 将内存内容保存到文件中
并在以后恢复所有内容:

  • 分配
    结构a
  • 将其重新解释为
    char
    s
  • 将内容加载到内存中
  • 重新解释\u cast
    将其返回到结构a

你想知道在特定的编译器上无效C++代码是否能保证没有问题的工作?没有人能在不看到微软的源代码的情况下回答这个问题。我想知道的是,由于未对齐的结构数据,会发生什么问题。@尼尔科克,我很抱歉,但是这个代码为我编译了UNER GCC,borland和intel以及msvc。@Alegnem我没说它没有编译。谢谢。(将是
“\x00\x00\x00\x01\x00\x00\x00\x00\x02\x03\x00\x00\x00\x00\x00\x04”
,因为第三个变量是
字符。是的,我知道。我想知道的是,不对齐的数据是否会导致一些问题。谢谢。这就是我想知道的。据我所知,读取未对齐的连续数据会使您多读取一到两次内存和大量移位。我很肯定你不需要每个字都读两遍。@Alegnem你说得对,我的措辞很糟糕。我写的是“执行内存访问操作”,而我的意思是“执行内存访问”。当然,是CPU做的,而不是程序员。我修正了它。IIRC“byte”在C/C++中的意思是“最小的可寻址单元”,不必是8位。谢谢。如今,对于x86或x64处理器,访问未对齐的数据是否存在问题?(mis)对齐只会降低性能(在x86/64上)。真正的问题是不同CPU架构的内存访问模式和具体内存模型可能不支持您的想法,然后我认为这没关系,因为我的代码不应该在x86或更高版本的x64之外的任何其他处理器体系结构中运行。这正是我遇到这个疑问时想要做的:尝试从文件中读取结构。但是当还原时,我没有得到“
reinterpret\u cast
it to
char
s”。@LHLaurini不需要从
char*
转换回
A*
。(1) 除非
char*
是从对齐的
A
中投射的,否则这是UB。(2) 在这里,它是,但它是毫无意义的!将文件加载到
a
的方法-如果它是可复制的,这很重要-是分配
a
&将文件作为一系列
char
s复制到它上面-通过读取
reinterpret\u cast(&a)
或一个单独的缓冲区,然后
memcpy
,等等(标准保证TC类型可在
char
buffers之间序列化)。然后阅读您已经拥有的
a
无需回溯。在适当的情况下,可以将副本优化为未对齐的强制转换
memcpy_s(sh, sizeof(A),
         "\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00", sizeof(A));