Rust 中的强制转换指针与 C++ 中的 reinterpret_cast 具有相同的行为吗?

Does casting pointers in Rust have the same behavior as reinterpret_cast in C++?

我在我的代码中定义了这个结构:

#[repr(align(4))]
struct MetaDataDefn {
  cncVersion: i32,
  toDriverBufferLength: i32,
  toClientsBufferLength: i32,
  counterMetadataBufferLength: i32,
  counterValuesBuferLength: i32,
  clientLivenessTimeout: i64,
  startTimestamp: i64,
  pid: i64
}

我有一个函数,它接受一个指向一块内存的原始指针,其中第一个字节对应于具有相同布局的结构。 我认为如果我将 u8 指针转换为结构指针,我会得到与在 C++ 中执行 reinterpret_cast 相同的结果。但是,我认为情况并非如此,我对这里发生的事情有点困惑。这是函数体(函数接收的指针是cncFilePtr):

let metadata = unsafe { cncFilePtr as *mut MetaDataDefn };

// This works
let cncVersion = unsafe { (*(cncFilePtr as *mut i32)) };
println!("CNC Version: {}", cncVersion);

//This prints a different number than the previous code
println!("CNC version (other way): {}", unsafe { (*metadata).cncVersion });

如您所见,将前 4 个字节转换为 i32 然后打印结果与将整个内容转换为 MetaDataDefn 并访问类型为 i32 的第一个成员(我的理解是两种方法应该给出相同的结果)

我的问题是:为什么结果不一样? Rust 中的指针转换与 C++ 中的 reinterpret_cast 不同(我来自 C++ 背景)?

通常,Rust 不保证结构在内存中的表示方式。它可以重新排序字段以使它们打包得更紧密,理论上甚至可以根据您的应用程序实际访问它们的方式优化字段顺序。

您可以通过添加 #[repr(C)] 属性来固定顺序,使其表现得像 C:

#[repr(C)]
#[repr(align(4))]
struct MetaDataDefn { ... }

这样,两个指针将给出相同的结果,因为这保证 cncVersion 首先出现。