Yapılarda güvenli örtüşen / birleşim alanları oluşturma

Aug 16 2020

C ++ 'da aşağıdaki gibi yapılar oluşturabilirim:

union Vector4
{
    struct { float x, y, z, w; };
    float data[4];
};

böylece verilere alanlar veya bitişik bir dizi olarak kolayca erişebilirim. Alternatif olarak, ilk alana bir işaretçi oluşturabilir xve işaretçiden bitişik bir dizi olarak okuyabilirim.

Numaralandırmalar olduğunu biliyorum, ancak ek masrafları ödeyemem. Ayrıca Rust'ta sendikalar oluşturabileceğimi de biliyorum, ancak kodumu unsafeonlara eriştiğim her yere koymam gerekiyor. Temel veriler her zaman yüzer olarak temsil edildiğinden kod güvensiz olmadığı için bunu yapmam gerektiğini düşünüyorum (ve #[repr(C)]derleyicinin alanların sırasını atmaması için C düzenine ihtiyacım var ).

Bunu Rust'ta nasıl uygulayabilirim, böylece alanlara adıyla erişebilirim, aynı zamanda tüm yapının bitişik belleğine kolay ve güvenli erişim sağlayabilirim? Bu mümkün değilse, güvenli bir şekilde bir yapı dilimi alabilmemin bir yolu var mı?

Yanıtlar

3 Locke Aug 17 2020 at 00:08

Güvenli sendika diye bir şey yoktur. Şahsen, sabit boyutlu tamsayı türleri dizileri arasında dönüşümün güvenli kabul edilmesi gerektiğini savunabilirim, ancak şu anda hiçbir istisna yoktur.

Olduğu söyleniyor, işte tamamen% 100 sendika değil Vector4. Gördüğünüz gibi Deref, güvenli olmayan kodu gizlemeye çalışır ve Vector4onu, içinde kullanıldığı bağlama göre bir yapı veya dizi olarak değerlendirebilmeniz için yapar. Dönüşüm de ideal değildir, ancak bunu haklı çıkarabileceğimi hissediyorum bu durumda. Böyle bir şey yapmayı seçerseniz, o zaman da uygulamak isteyebilirsiniz DerefMut.

use std::ops::Deref;

// I'm not sure if the repr(C) is needed in this case, but I added it just in case.
#[repr(C)]
pub struct Vector4<T> {
    pub x: T,
    pub y: T,
    pub z: T,
    pub w: T,
}

impl<T> Deref for Vector4<T>
where
    T: Copy + Sized,
{
    type Target = [T; 4];

    fn deref(&self) -> &Self::Target {
        use std::mem::transmute;
        unsafe { transmute(self) }
    }
}

pub fn main() {
    let a = Vector4{
        x: 37,
        y: 21,
        z: 83,
        w: 94,
    };

    println!("{:?}", &a[..]);
    // Output: [37, 21, 83, 94]
}