rustmemory-layout

Precise memory layout control in Rust?


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 C#, I have the StructLayout attribute, and in C/C++, I could use various compiler extensions. I could verify the memory layout by checking the byte offset of expected value locations.

I'd like to write OpenGL code employing custom shaders, which needs precise memory layout. Is there a way to do this without sacrificing performance?


Solution

  • 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,
        };
    
        // addr_of! used here due to unaligned references being UB: https://github.com/rust-lang/rust/issues/82523
        let a_ptr: *const u8 = std::ptr::addr_of!(obj.a);
        let b_ptr: *const u16 = std::ptr::addr_of!(obj.b);
        let c_ptr: *const u32 = std::ptr::addr_of!(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