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?
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