我在代码中定义了这个结构:
#[repr(align(4))]
struct MetaDataDefn {
cncVersion: i32,
toDriverBufferLength: i32,
toClientsBufferLength: i32,
counterMetadataBufferLength: i32,
counterValuesBuferLength: i32,
clientLivenessTimeout: i64,
startTimestamp: i64,
pid: i64
}
我有一个函数,它使用原始指针指向一块内存,其中前几个字节对应于具有相同布局的结构。 我以为,如果将u8指针转换为struct指针,我将得到与在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 ++背景)?
答案 0 :(得分:2)
通常,Rust不保证结构在内存中的表示方式。它可以对字段进行重新排序以使它们更紧密地包装,并且理论上甚至可以根据应用程序实际访问它们的方式来优化字段顺序。
您可以通过添加#[repr(C)]
属性来固定顺序,使其表现得像C:
#[repr(C)]
#[repr(align(4))]
struct MetaDataDefn { ... }
这样,两个指针将给出相同的结果,因为这保证了cncVersion
首先出现。