我目前正在编写一个Vulkan渲染器,我刚刚意识到我应该只接受那些类型repr(C)
,但据我所知,在编译时无法实际检查它.
struct Vertex {
x: f32,
y: f32,
b: Box<f32>
}
#[repr(C)]
struct Vertex2 {
x: f32,
y: f32,
b: Box<f32>
}
fn to_bytes<T>(t: &T) -> &[u8]{
let p: *const T = t;
let p = p as *const u8;
unsafe{
std::slice::from_raw_parts(p, std::mem::size_of::<T>())
}
}
fn main() {
let v = Vertex{x: 42.0, y: 0.0, b: Box::new(42.0)};
let v2 = Vertex2{x: 42.0, y: 0.0, b: Box::new(42.0)};
println!("{:?}", to_bytes(&v));
println!("{:?}", to_bytes(&v2));
}
Run Code Online (Sandbox Code Playgroud)
经过几次尝试,我终于可以看到repr(c)
和之间的区别,repr(rust)
但只有当我使用了Box
.
repr(C)
和之间有什么区别repr(rust)
?我可以假设如果一个类型只包含其他POD类型,那么布局将与C中的相同吗?
例:
let slice = base.device
.map_memory::<Vertex>(vertex_input_buffer_memory,
0,
vertex_input_buffer_info.size,
vk::MemoryMapFlags::empty())
.unwrap();
slice.copy_from_slice(&vertices);
Run Code Online (Sandbox Code Playgroud)
我正在填写一个缓冲区,我交给Vulkan,所以我认为这里的布局可能很重要.
您在程序输出中看到的差异不是由于内存布局.Box<T>
heap分配并存储指向堆内容的指针,因此您打印的是指针.由于Box<T>
不执行任何实习/对象池,这两个地址当然是不同的.可能有点令人困惑的是地址彼此如此接近.我想这只与jmalloc有关,这是分配器Rust使用的,它有用于小分配的密集池.
我可以假设如果一个类型只包含其他POD类型,那么布局将与C中的相同吗?
不,你几乎不能假设Rust的类型内存布局.故意不指定这允许优化,例如字段重新排序.即使现在,repr(Rust)
匹配repr(C)
非常接近,你不能认为它将永远像那样.