【问题标题】:Is it safe to cast `struct` to a slice in rust?将“struct”投射到生锈的切片上是否安全?
【发布时间】:2021-04-24 04:07:53
【问题描述】:

我有一些struct,类似这样的:

struct MyStruct<T> {
    field1: T,
    field2: T,
    field3: T,
}

我对@9​​87654323@ 的了解和确信:

  • 所有字段的类型相同;
  • 所有字段均为Sized
  • 每个struct(本例中为3)的准确字段数;

在我的项目中,像切片一样访问structs 可能很有用。所以我做了什么:

impl<T> AsRef<[T]> for MyStruct<T> {
    fn as_ref(&self) -> &[T] {
        let ptr = self as *const Self;
        let ptr2 = ptr as *const T;
        unsafe { std::slice::from_raw_parts(ptr2, 3) }
    }
}

现在我可以像这样访问MyStruct 的字段:

let s = MyStruct { field1: 1.0, field2: 2.0, field3: 3.0 };
s.as_ref()[1]

我已经在devrelease 模式下测试了一些示例,但没有发现任何错误。我仍然不确定这种指针魔术。

Rust 不能保证内存布局会保持字段的顺序。另一方面,据我所知,只有当struct 的字段大小不同且需要对齐时才会发生这种情况。

所以我真的很好奇:

  1. 是否存在任何违反防锈安全保证的情况?
  2. 此变体与下一个变体之间是否存在安全或性能差异?
  3. 我应该使用union 来代替这个技巧吗?
impl<T> AsRef<[T]> for MyStruct<T> {
    fn as_ref(&self) -> &[T] {
        let tmp: &[T; 3] = unsafe { std::mem::transmute(self) };
        tmp.as_ref()
    }
}

【问题讨论】:

    标签: rust unsafe memory-layout


    【解决方案1】:
    1. 是否存在任何违反防锈安全保证的情况?

    是的,不保证订单。尽管不太可能改变,但 Rust 的 ABI 并不稳定,因此未来版本的 Rust 编译器可能会做不同的事情。

    您可以强制使用 C ABI,这将使其安全:

    #[repr(C)]
    struct MyStruct<T> {
        field1: T,
        field2: T,
        field3: T,
    }
    

    避免unsafe 的一种可能更好的方法是将字段存储在数组中,然后提供访问器:

    struct MyStruct<T> {
        fields: [T; 3],
    }
    
    impl<T> MyStruct<T> {
        fn field1(&self) -> &T {
            &self[0]
        }
    
        fn field1_mut(&mut self) -> &mut T {
            &mut self[0]
        }
    
        // etc, you could generate these with a macro if there are a lot
    }
    
    1. 此变体与下一个变体之间是否存在安全或性能差异?

    这些很可能编译成相同的东西。如果您不确定,请进行测试。对于简单的事情,您可以将代码粘贴到 rust.godbolt.org 并比较程序集。

    1. 我应该使用 Union 而不是这个技巧吗?

    这也只有使用#[repr(C)] 才安全。我看不出在这里使用union 有什么明显的好处,但这意味着你必须使用甚至更多 unsafe 代码,所以这似乎不是一个好主意.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-09
      • 2015-08-19
      • 1970-01-01
      相关资源
      最近更新 更多