Important

会合并到基础篇

1 类型

Diagram
fn main() {
    // 10 00000100 00000011 00000001
    let mut a = 33817345i32;
    struct FourI8 {
        first: i8,
        second: i8,
        third: i8,
        fourth: i8,
    }
    // 将变量a的地址 转换为一个指针 ,指针类型是i32,这个就是a原来的内存读取方式
    // 然后再将这个指针 进行类型转换, 转换为 结构体的方式来读取 a 所在的那块内存
    let b = &mut a as *mut i32 as *mut FourI8;
    unsafe {
        println!(
            "{} {} {} {}",
            (*b).first,
            (*b).second,
            (*b).third,
            (*b).fourth
        );
        (*b).first = 2;
        // 10 00000100 00000011 00000010
        println!("{:b}", a);
    }
}

2 内存对齐

struct A {
    a: u8,
    b: u32,
    c: u16,
}
// 这种对齐 12个字节
struct A {
    a: u8,
    _pad1: [u8; 3], // to align `b`
    b: u32,
    c: u16,
    _pad2: [u8; 2], // to make overall size multiple of 4
}
// 这种对齐 8个字节
struct A {
    b: u32,
    c: u16,
    a: u8,
    _pad: u8,
}
use std::mem;

struct A {
    a: u8,
    b: u32,
    c: u16,
}

fn main() {
    let x = A { a: 1, b: 2, c: 3 };
    println!("{}", mem::size_of_val(&x)); // 8
    // 0x0x7ff7bf6930be-0x0x7ff7bf6930b8-0x0x7ff7bf6930bc
    // 也就是说实际优化成
    struct A {
        b: u32,
        c: u16,
        a: u8,
    }
    println!("0x{:p}-0x{:p}-0x{:p}", &x.a, &x.b, &x.c);
}
Diagram

3 Box

fn main() {
    // 5 是在 堆上分配的, 栈上的变量b 指向了它
    let b = Box::new(5);
    let a = 11i64;
    let c = Box::new(&a);
    println!("b的值 = {:p}", b);
    println!("c的地址 : {:p}", &c);
    println!("a的地址 : {:p}", &a);
    println!("c的值: {:p}", c);
    let d = &c as *const Box<&i64> as *const u64;
    unsafe {
        // c的值是个地址,指向堆上的内存
        println!("c的值: 0x{:x}", *d);
        let dd = *d as *const u64;
        // c的值是地址,该地址所在内存 存的是 a的地址
        println!("0x{:x}", *dd);
    }
}
Diagram

4 Vec,[T;N],&[T]

fn main() {
    let mut vec: Vec<i32> = vec![1, 2, 3, 4];
    let arr = [1, 2, 3, 4];
    vec.push(5);
    let (ptr, len, cap) = (vec.as_ptr(), vec.len(), vec.capacity());
    println!("Vec 的指针: {:?}", ptr);
    println!("Vec 的长度: {}", len);
    println!("Vec 的容量: {}", cap);
    // 等价于 let slice_vec:&[i32]=&v;
    // let slice_vec = &v[..];
    // [T] 本身表示动态大小, &[T] 切片后,确定了长度
    let slice_vec = &vec as &[i32];

    // 等价于 let slice_arr:&[i32]=&arr;
    // let slice_arr = &arr[..];
    let slice_arr = &arr as &[i32];
    println!(
        "vec的ptr:{:p}-slice_vec的ptr:{:p}-{}",
        vec.as_ptr(),
        slice_vec.as_ptr(),
        slice_vec.len()
    );
    println!(
        "arr地址:{:p}-slice_arr的ptr:{:p}-{}",
        &arr,
        slice_arr.as_ptr(),
        slice_arr.len()
    );

    struct SliceStruct {
        a: usize,
        b: usize,
    }

    unsafe {
        let b = &slice_vec as *const &[i32] as *const SliceStruct;
        // a: cap, b:ptr,c:len
        println!("0x{:x}-0x{:x}", (*b).a, (*b).b);
    }
    struct VecStruct {
        a: usize,
        b: usize,
        c: usize,
    }

    unsafe {
        let b = &vec as *const Vec<i32> as *const VecStruct;
        // a: cap, b:ptr,c:len
        println!("0x{:x}-0x{:x}-0x{:x}", (*b).a, (*b).b, (*b).c);
    }
}
Diagram

5 String,&str

fn main() {
    let a = "hello";
    let b = "world".to_string();
    println!("{:p}-{:p}", &a, a.as_ptr());
    println!("{:p}-{:p}-{}-{}", &b, b.as_ptr(), b.capacity(), b.len());
    unsafe {
        let c = a.as_ptr() as *const u8;
        println!("{:p}", c);
        let mut d;
        for i in 0..10 {
            // 一个字节一个字节的打印
            d = c.add(i);
            // h-e-l-l-o-w-o-r-l-d-
            print!("{}-", *d as char);
        }
        println!("")
    }

    let e = &b[1..];
    println!("{:p}-{:p}", &e, e.as_ptr());

    struct StringStruct {
        a: usize, // cap
        b: usize, // ptr
        c: usize, // len
    }
    let mut s = "hello".to_string();
    s.push_str("x");
    // 6-10
    println!("{}-{}", s.len(), s.capacity());
    let b = &s as *const String as *const StringStruct;
    unsafe {
        // 0xa-0x7f8fbb705f90-0x6
        println!("0x{:x}-0x{:x}-0x{:x}", (*b).a, (*b).b, (*b).c);
    }
}
Diagram

6 &’static

1fn foo() -> &'static [u8] {
    &[1, 2, 3]
}
fn main(){
    let b = 1;
    println!("b: {:p}", &b);

    let a = foo();
    // a: 0x10fa97aa0
    println!("a: {:p}", a); // 只读内存区
    let c = Box::new(2i64);
    println!("c: {:p}", c.as_ref());
    let d = &c as *const Box<i64> as *const u64;
    unsafe {
        // c的值是个地址,指向堆上的内存
        println!("c指向堆上的地址: 0x{:x}", *d);
    }
    let s = "abc";
    //  s: 0x10fa97aa3 ,  a的 [1,2,3] 占用了3个字节 刚好
    println!(" s: {:p}", s.as_ptr()); // 只读内存区
}
1
a.当看到这个可以编译通过时,我就猜测是在编译期直接在只读内存区写入数据,这和字符串字面量实际是一样的
b.当 foo()改成返回 &[b'a', b'b', b'c'], 你会发现 变量s 关联的只读区和 foo()关联的只读区 一样,直接复用了

7 TODO

Back to top