Precise memory layout control in Rust?

后端 未结 3 1765
野趣味
野趣味 2021-02-03 22:14

As far as I know, the Rust compiler is allowed to pack, reorder, and add padding to each field of a struct. How can I specify the precise memory layout if I need it?

In

相关标签:
3条回答
  • 2021-02-03 23:03

    As described in the FFI guide, you can add attributes to structs to use the same layout as C:

    #[repr(C)]
    struct Object {
        a: i32,
        // other members
    }
    

    and you also have the ability to pack the struct:

    #[repr(C, packed)]
    struct Object {
        a: i32,
        // other members
    }
    

    And for detecting that the memory layout is ok, you can initialize a struct and check that the offsets are ok by casting the pointers to integers:

    #[repr(C, packed)]
    struct Object {
        a: u8,
        b: u16,
        c: u32, // other members
    }
    
    fn main() {
        let obj = Object {
            a: 0xaa,
            b: 0xbbbb,
            c: 0xcccccccc,
        };
        let a_ptr: *const u8 = &obj.a;
        let b_ptr: *const u16 = &obj.b;
        let c_ptr: *const u32 = &obj.c;
    
        let base = a_ptr as usize;
    
        println!("a: {}", a_ptr as usize - base);
        println!("b: {}", b_ptr as usize - base);
        println!("c: {}", c_ptr as usize - base);
    }
    

    outputs:

    a: 0
    b: 1
    c: 3
    
    0 讨论(0)
  • 2021-02-03 23:08

    You also can set memory layout for "data-carrying enums" like this.

    #[repr(Int)]
    enum MyEnum {
        A(u32),
        B(f32, u64),
        C { x: u32, y: u8 },
        D,
    }
    

    Details are described in manual and RFC2195.

    • https://rust-lang.github.io/unsafe-code-guidelines/layout/enums.html
    • https://rust-lang.github.io/rfcs/2195-really-tagged-unions.html#motivation
    0 讨论(0)
  • 2021-02-03 23:17

    There's no longer to_uint. In Rust 1.0, the code can be:

    #[repr(C, packed)]
    struct Object {
        a: i8,
        b: i16,
        c: i32, // other members
    }
    
    fn main() {
        let obj = Object {
            a: 0x1a,
            b: 0x1bbb,
            c: 0x1ccccccc,
        };
    
        let base = &obj as *const _ as usize;
        let a_off = &obj.a as *const _ as usize - base;
        let b_off = &obj.b as *const _ as usize - base;
        let c_off = &obj.c as *const _ as usize - base;
    
        println!("a: {}", a_off);
        println!("b: {}", b_off);
        println!("c: {}", c_off);
    }
    
    0 讨论(0)
提交回复
热议问题