我试图更好地理解 Rust 的原始指针,我认为下面的代码会失败(很抱歉可能出现 UB)[Playground]:
fn main() {
println!("size of * const u32 ->{}", std::mem::size_of::<* const u32>());
println!("size of * const [u32;13] ->{}", std::mem::size_of::<* const [u32;13]>());
println!("size of * const [u32] ->{}", std::mem::size_of::<* const [u32]>());
let x = 1u32;
let arr = [1,2,3,4,5,6,7,8, 9, 10, 11, 12, 13u32];
let px: * const u32 = &x;
let parr: * const [u32;13] = &arr;
let slice: &[u32] = &arr;
let pslice: * const [u32] = slice;
unsafe { println!("px -> {:?}", px.as_ref()) };
unsafe { println!("parr -> {:?}", parr.as_ref()) };
unsafe { println!("pslice -> {:?}", pslice.as_ref()) };
//
println!("How could this work:");
let pslice2: * const [u32] = parr; // How could this work ?
unsafe { println!("pslice2 -> {:?}", pslice2.as_ref()) }; // How could this work ?
}
但它甚至与 miri 一起工作:
Standard Error
Compiling playground v0.0.1 (/playground)
Finished dev [unoptimized + debuginfo] target(s) in 1.16s
Running `/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner target/miri/x86_64-unknown-linux-gnu/debug/playground`
Standard Output
size of * const u32 ->8
size of * const [u32;13] ->8
size of * const [u32] ->16
px -> Some(1)
parr -> Some([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13])
pslice -> Some([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13])
How could this work:
pslice2 -> Some([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13])
我对切片指针的大小为 16 而数组指针的大小为 8 并不感到惊讶,因为类型不包括数据的大小。但是为什么
let pslice2: * const [u32] = parr;
之后的代码 let parr: * const [u32;13] = &arr;
会被接受以及为什么 pslice.as_ref()
会产生一些数据?
我想从
pslice2
(一个简单的指针(仅地址))初始化 parr
(一个胖指针(地址+大小))可能看起来很奇怪,因为 parr
中缺少的 size信息对于
是必需的pslice2
。
但是这个信息是编译器知道的;这就是为什么
parr
能够访问数组中的所有元素。pslice2
初始化期间,编译器会简单地提供“缺失”size 信息。pslice2
是全胖指针(地址+大小),然后可以访问数组中的所有元素。