Precise memory layout control in Rust?

时光怂恿深爱的人放手 提交于 2021-02-05 20:53:11

问题


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?


回答1:


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



回答2:


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);
}



回答3:


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


来源:https://stackoverflow.com/questions/26271151/precise-memory-layout-control-in-rust

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!