Struct Rust:使用两个u8结构字段作为u16

Struct Rust:使用两个u8结构字段作为u16,struct,rust,unions,Struct,Rust,Unions,对于Gameboy仿真器,寄存器a和F有两个u8字段,但它们有时可以作为AF(组合u16寄存器)访问 在C中,看起来您可以执行以下操作: struct{ 联合{ 结构{ 无符号字符f; 无符号字符a; }; 无符号短af; }; }; (摘自) 在Rust中是否有一种方法,理想情况下不存在不安全的,即可以访问两个U8作为寄存器.a/寄存器.f,但也可以将它们用作u16寄存器.af?我可以为您提供几种方法。第一个是直接的不安全模拟,但没有样板,第二个是安全的,但明确的 rust中的活接头非常相似

对于Gameboy仿真器,寄存器a和F有两个u8字段,但它们有时可以作为AF(组合u16寄存器)访问

在C中,看起来您可以执行以下操作:

struct{
联合{
结构{
无符号字符f;
无符号字符a;
};
无符号短af;
};
};
(摘自)


在Rust中是否有一种方法,理想情况下不存在
不安全的
,即可以访问两个U8作为
寄存器.a
/
寄存器.f
,但也可以将它们用作u16
寄存器.af

我可以为您提供几种方法。第一个是直接的不安全模拟,但没有样板,第二个是安全的,但明确的

  • rust中的活接头非常相似,因此可以将其转换为:
  • 或者,您也可以手动执行包装在结构中的所有显式强制转换:

  • 非常感谢。为了便于使用,我可能会使用第一个示例,即使
    不安全的
    代码不受欢迎。@DeeBo第二个示例更便于移植,因为它明确说明了如何使用little endian打包;但在实践中,现在使用的big-endian机器并不多。是的,我最终选择了介于两者之间的一段时间,因为我不想把不安全的东西放在任何地方。我将结构字段.a和.f作为没有getter的普通U8,然后是一个get_af()函数,没有“Self”链接。我认为这是最有意义的。我在这个问题后的实施情况可以在这里找到:
    
    #[repr(C)]
    struct Inner {
        f: u8,
        a: u8,
    }
    
    #[repr(C)]
    union S {
        inner: Inner,
        af: u16,
    }
    
    // Usage:
    
    // Putting data is safe:
    let s = S { af: 12345 };
    // but retrieving is not:
    let a = unsafe { s.inner.a };
    
    #[repr(transparent)]
    // This is optional actually but allows a chaining,
    // you may remove these derives and change method
    // signatures to `&self` and `&mut self`.
    #[derive(Clone, Copy)]
    struct T(u16);
    
    impl T {
        pub fn from_af(af: u16) -> Self {
            Self(af)
        }
        
        pub fn from_a_f(a: u8, f: u8) -> Self {
            Self::from_af(u16::from_le_bytes([a, f]))
        }
    
        pub fn af(self) -> u16 {
            self.0
        }
    
        pub fn f(self) -> u8 {
            self.0.to_le_bytes()[0]
        }
    
        pub fn set_f(self, f: u8) -> Self {
            Self::from_a_f(self.a(), f)
        }
    
        pub fn a(self) -> u8 {
            self.0.to_le_bytes()[1]
        }
    
        pub fn set_a(self, a: u8) -> Self {
            Self::from_a_f(a, self.f())
        }
    }
    
    // Usage:
    
    let t = T::from_af(12345);
    let a = t.a();
    
    let new_af = t.set_a(12).set_f(t.f() + 1).af();