Skip to content

Latest commit

 

History

History
93 lines (70 loc) · 3.78 KB

File metadata and controls

93 lines (70 loc) · 3.78 KB

Repr attribute

The repr attribute allows us to control memory layouts including those of structs. This study examined how each of the options we can specify affects memory layouts.

Study results

The memory layout of a struct is shown below:

  • #[repr(Rust)]

    • Regardless of the order in which the fields are defined in the source code, they are arranged on the memory in descending order of their size with an alignment adhered.
  • #[repr(C)]

    • A memory layout compatible with C/C++ language is used and the fields are arranged on the memory, with an alignment adhered, in the order in which they are defined in the source code.
  • #[repr(packed(1))]

    • This option enables us to specify a memory alignment and the fields are arranged on the memory, with an alignment not adhered, in the order in which they are defined in the source code.

Details

#[repr(Rust)]

The value #[repr(Rust)] is the default one used when specifying no explicit attribute value and, in the case of the sample code, the memory layout of the struct should be as shown below. The i8 type variable y has memory of 2 bytes allocated also due to effects of alignment, resulting in the total used memory size of 32 bytes. Regardless of the order in which the variables are defined in the source code, they are arranged on the memory in descending order of their size. Variables of the same size are arranged on the memory in the order in which they are defined in the source code.

repr_attribute

#[repr(C)]

When specifying #[repr(C)], a memory layout compatible with C/C++ language is used. The memory layout of the struct in the sample program is shown below. The arrangement on the memory is consistent with the order of definition in the source code and, as in the case of #[repr(Rust)], the i8 type variable y has memory of 2 bytes allocated also due to effects of alignment, resulting in the total used memory size of 32 bytes. Note that unused memory area is not initialized with 0x00 and random data 0x72 originally placed there is left unchanged. In 32-bit binaries, we can find no differences from 64-bit binaries in the memory layout, except the size of the management struct for name, which is managed in units of 4 bytes. In size-minimized binaries, we can also find no differences from the other types of binaries in the size and memory layout of the struct.

repr_attribute

#[repr(packed(1))]

The #[repr(packed(1))] option enables us to specify an alignment for memory. The memory layout of the struct in the sample program is shown below. Unlike Rust and C language, the i8 type variable y has one-byte memory allocated, resulting in the total used memory size of seven bytes. Similarly to C language, the arrangement on memory is consistent with the order of definition in the source code. We can find no differences between cases of 32-bit and size-minimized binaries.

repr_attribute

Sample program we used

use std::mem;

#[derive(Debug)]
#[repr(Rust)]
struct RustStruct {
    x: i16,
    y: i8,
    z: i32,
    name: String,
}

#[derive(Debug)]
#[repr(C)]
struct CStruct {
    x: i16,
    y: i8,
    z: i32,
    name: String,
}

#[derive(Debug)]
#[repr(packed(1))]
struct Packed1Struct {
    x: i16,
    y: i8,
    z: i32,
}

fn main() {
    let rust_struct = RustStruct {x:1, y:3, z:5, name: String::from("Rust Struct")};
    let c_struct = CStruct {x:2, y:4, z:6, name: String::from("C Struct")};
    let packed_1_struct = Packed1Struct {x:1, y:2, z:3};

    println!("{:?}", rust_struct);
    println!("size: {}", mem::size_of::<RustStruct>());
    println!("{:?}", c_struct);
    println!("size: {}", mem::size_of::<CStruct>());
    println!("{:?}", packed_1_struct);
    println!("size: {}", mem::size_of::<Packed1Struct>());
}