Rust:使用两个 u8 结构字段作为 u16
Rust: Using two u8 struct fields as a u16
对于 Gameboy 模拟器,寄存器 A 和 F 有两个 u8 字段,但它们有时可以作为 AF(一个组合的 u16 寄存器)访问。
在 C 中,看起来你可以这样做:
struct {
union {
struct {
unsigned char f;
unsigned char a;
};
unsigned short af;
};
};
(取自here)
Rust 中有没有一种方法,理想情况下没有 unsafe
,既可以访问两个 u8 作为 registers.a
/registers.f
,又可以将它们用作 u16 registers.af
?
我可以给你几个方法。第一个是直接的不安全模拟但没有样板,第二个是安全但明确的。
- rust 中的 union 非常相似,因此您可以将其翻译为:
#[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();
对于 Gameboy 模拟器,寄存器 A 和 F 有两个 u8 字段,但它们有时可以作为 AF(一个组合的 u16 寄存器)访问。
在 C 中,看起来你可以这样做:
struct {
union {
struct {
unsigned char f;
unsigned char a;
};
unsigned short af;
};
};
(取自here)
Rust 中有没有一种方法,理想情况下没有 unsafe
,既可以访问两个 u8 作为 registers.a
/registers.f
,又可以将它们用作 u16 registers.af
?
我可以给你几个方法。第一个是直接的不安全模拟但没有样板,第二个是安全但明确的。
- rust 中的 union 非常相似,因此您可以将其翻译为:
#[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();