2017-03-16 860 views
2

我目前正在编写一个Vulkan渲染器,我只是意识到我应该只接受类型为repr(C),但据我所知在编译时没有办法真正检查它。repr(C)和repr(rust)之间的区别是什么?

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)); 
} 

Playground

试了几次后,我终于可以看到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); 

Source

我填,我交给福尔康一个缓冲区,所以我认为这里的布局可能是重要的。

+0

“*我应该只接受类似'repr(C)'*” - >你能澄清一下吗?您在某些方法中接受泛型类型,并且需要这些类型为'repr(C)'?为什么? –

+0

我不认为Rust会保证Rust将使用与C相同的数据表示。 – user4815162342

+0

@LukasKalbertodt我不完全确定你的意思,但我在我的问题中添加了一个例子。这里的'Vertex'确实应该匹配着色器将要使用的C布局吗?我不太确定'#[repr(C)]'由于不同的包装会导致不同的尺寸。 –

回答

4

您在程序输出中看到的差异不是由于内存布局。 Box<T>堆分配并存储一个指向堆内容的指针,所以你打印的是指针。由于Box<T>不执行任何实施/对象池,所以这两个地址当然是不同的。可能有点令人困惑的是,地址彼此之间如此接近。我想猜想这与jmalloc有关,Rust使用的分配器,它为小分配密集存储池。

我可以假设,如果一个类型只包含其他POD类型,那么布局将与C中的相同?

你几乎不能承担有关的类型锈病的内存布局什么。这是故意没有指定为允许优化,如字段重新排序。即使现在repr(Rust)匹配repr(C)非常密切,你不能认为它会永远那样。

+0

哦,对,我不敢相信我没注意到。我想我可以使用proc宏来动态实现一些特征,如果类型具有'#[repr(C)]'。 –

+2

特别是,最近一段时间,字段已经重新排序,尽管它已经暂时退出:https://internals.rust-lang.org/t/rolling-out-or-unrolling-struct-field-reorderings/4485 –

相关问题