将结构转换为数组是否合法?

Is it legal to cast a struct to an array?

考虑以下因素:

// Just a sequence of adjacent fields of same the type
#[repr(C)]
#[derive(Debug)]
struct S<T> {
    a : T,
    b : T,
    c : T,
    d : T,
}

impl<T : Sized> S<T> {
    fn new(a : T, b : T, c : T, d : T) -> Self {
        Self {
            a,
            b,
            c,
            d,
        }
    }
    // reinterpret it as an array
    fn as_slice(&self) -> &[T] {
        unsafe { std::slice::from_raw_parts(self as *const Self as *const T, 4) }
    }
}

fn main() {
    let s = S::new(1, 2, 3, 4);
    
    let a = s.as_slice();
    
    println!("s :: {:?}\n\
              a :: {:?}", s, a);
}

是的,它安全且便携,但非常大的 T 除外(在下面修复)。 std::slice::from_raw_parts 文档的安全部分中列出的要点中的 None 在这里是一个问题:

  • 数据指针对 mem::size_of::<T>() * 4 有效,这是 S<T> 的大小,并且正确对齐。

    • 所有项目都在同一个分配对象中,因为它们在同一个结构中。
    • 指针不为空,因为它是从安全的 &self 参数转换过来的,并且正确对齐,因为 S<T> 具有(至少)[=11= 的对齐方式].
  • data参数肯定指向4个连续初始化的Ts,因为S在你的struct中被标记为#[repr(C)] which is defined such that, no将引入填充。 (repr(Rust) 不作此类保证)。

  • 引用的内存在引用的生命周期内不会发生变化,这是由借用检查器保证的。

  • 切片的总大小不得大于isize::MAX。代码不会对此进行检查,因此从技术上讲这是一个安全漏洞。可以肯定的是,在 unsafe:

    之前添加对 as_slice 的检查
    assert!(std::mem::size_of::<S<T>>() <= isize::MAX as _);
    

    检查通常会被优化。