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
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
You also can set memory layout for "data-carrying enum
s" like this.
#[repr(Int)]
enum MyEnum {
A(u32),
B(f32, u64),
C { x: u32, y: u8 },
D,
}
Details are described in manual and RFC2195.
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);
}