-
Rust❤️Getting a pointer to a field of an enum | Reddit코딩Coding/★Rust★기초★Syntax 2022. 6. 27. 10:02728x90
이게 기본 코드
enum Foo { A(i32), B(u8), } macro_rules! offset_of { ($($tt:tt)*) => { { let base = $($tt)*(unsafe { ::std::mem::uninitialized() }); let offset = match base { $($tt)*(ref inner) => (inner as *const _ as usize) - (&base as *const _ as usize), _ => unreachable!(), }; ::std::mem::forget(base); offset } } } fn main() { println!("{}", offset_of!(Foo::A)); }
결과Compiling playground v0.0.1 (/playground) warning: use of deprecated function `std::mem::uninitialized`: use `mem::MaybeUninit` instead --> src/main.rs:11:53 | 11 | let base = $($tt)*(unsafe { ::std::mem::uninitialized() }); | ^^^^^^^^^^^^^ ... 24 | println!("{}", offset_of!(Foo::A)); | ------------------ in this macro invocation | = note: `#[warn(deprecated)]` on by default = note: this warning originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) warning: variant is never constructed: `B` --> src/main.rs:5:5 | 5 | B(u8), | ^^^^^ | = note: `#[warn(dead_code)]` on by default warning: `playground` (bin "playground") generated 2 warnings Finished dev [unoptimized + debuginfo] target(s) in 0.73s Running `target/debug/playground` Standard Output 4
레딧 자료는 여기서 더 업그레이드 해야함
Getting a pointer to a field of an enum
I'm trying to initialize fields of *an enum variant* one by one, and I'm having trouble doing it soundly. I have a working implementation, but it causes UB (Miri doesn't like it).
Here is the de-macro'd code:let cff_data_ptr = addr_of_mut!(*match &mut *outline_builder_ptr { OutlineBuilder::Cff { cff_data, .. } => cff_data as *mut Cow<'a, [u8]>, _ => unreachable_unchecked() });
let cff_data_ptr = addr_of_mut!(*match &mut *outline_builder_ptr {
OutlineBuilder::Cff { cff_data, .. } => cff_data as *mut Cow<'a, [u8]>,
_ => unreachable_unchecked()
});
Notice that it has to take an `&mut` reference in order to match on it. This is the UB.
Is there any way to do this without creating a reference? I'm trying to get a pointer to the `cff_data` field in the uninitialized memory.
And before you comment about it: yes, I am setting the discriminant correctly afterwards. After initializing all the fields, I read them back into a fully constructed instance of the enum which I then write back, which fills in the discriminant.
There is a [StackOverflow answer from 2017](https://stackoverflow.com/a/41824023) that describes this scenario, I am unsure if the situation has changed since then.
https://www.reddit.com/r/rust/comments/vkb663/getting_a_pointer_to_a_field_of_an_enum/?utm_source=share&utm_medium=ios_app&utm_name=iossmf
중간에 나오는 내용 코드#![allow(dead_code)] use std::mem::{transmute, MaybeUninit, size_of}; use std::ptr::addr_of_mut; #[derive(Debug)] #[repr(C, u8)] enum Foo { A(u16, u16), B(u64) } #[repr(C)] struct FooRepr { tag: FooTag, payload: FooPayload, } #[repr(u8)] enum FooTag { A, B } #[repr(C)] union FooPayload { a: APayload, b: u64, } #[derive(Clone, Copy)] #[repr(C)] struct APayload { x: u16, y: u16, } fn main() { let mut x_repr: MaybeUninit<FooRepr> = MaybeUninit::uninit(); // init payload field x unsafe { let ptr = x_repr.as_mut_ptr(); addr_of_mut!((*ptr).payload.a.x).write(12); } // init payload field y unsafe { let ptr = x_repr.as_mut_ptr(); addr_of_mut!((*ptr).payload.a.y).write(13); } // init tag unsafe { let ptr = x_repr.as_mut_ptr(); addr_of_mut!((*ptr).tag).write(FooTag::A); } let x_repr = unsafe { x_repr.assume_init() }; let x: Foo = unsafe { transmute(x_repr) }; println!("{x:?}"); } // Debug traits that print out the bytes for debugging use std::mem::transmute_copy; impl std::fmt::Debug for FooRepr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { write!(f, "FooRepr {{ tag: {:?}, payload: {:?} }}", self.tag, self.payload) } } impl std::fmt::Debug for FooPayload { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { let bytes = unsafe { transmute_copy::<Self, [u8; size_of::<Self>()]>(self) }; write!(f, "{:?}", bytes) } } impl std::fmt::Debug for FooTag { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { let bytes = unsafe { transmute_copy::<Self, [u8; size_of::<Self>()]>(self) }; write!(f, "{:?}", bytes) } }
결과Standard Error Compiling playground v0.0.1 (/playground) Finished release [optimized] target(s) in 1.22s Running `target/release/playground` Standard Output A(12, 13)
❤️repr(Rust) 대해서
https://doc.rust-lang.org/nomicon/repr-rust.html
다른글
Rust Default
❤️Initialize Variables in a Rust Struct -
https://economiceco.tistory.com/m/14264
반응형'코딩Coding > ★Rust★기초★Syntax' 카테고리의 다른 글
Rust❤️코딩하는 컴퓨터의 환경설정(std::env) 이것저것 알아보기 (0) 2022.06.29 보고 배울게 많은 Rust프로그래밍 영상-Tsoding Daily 👍실력 정말 좋다 (0) 2022.06.29 NeoVim as a Rust IDE❤️ (0) 2022.06.29 Rust 3 situations ( Variable bindings, Pointers, Threads (0) 2022.06.28 Translating C++ & Rust❤️ (0) 2022.06.27 Introduction to Rust - Part 15: ❤️Futures | Rhymu's Videos (0) 2022.06.27 Rust❤️ 벡터 안에 짝수 인 값의 인덱스 값을 결과값으로 받고 싶을 때 iter().position(|&x| x % 2 == 0)closure (0) 2022.06.23 Rust ❤️Tutorial 영어로 써 줘서 불만함 (0) 2022.06.22