Kos
Kos

Reputation: 1778

How to make layout of struct linear?

It seems the layout of a struct is not linear. Looks like fields of struct in memory are not in the same order as they are written into the definition of the structure. Is there a way to ask the compiler to preserve the order of fields? What other solution of the problem can you suggest? Any reading?

use std::borrow::Borrow;

fn main()
{
  let header = ObjectHeader
  {
    x : 1,
    h : 2,
    a : 3,
    f : 4,
    w : 5,
    body : (),
  };

  let object = header.form();
  let borrowed_header : &ObjectHeader = object.borrow();
  dbg!( borrowed_header );

}

//

#[ derive( Debug, Clone ) ]
pub struct ObjectGeneric< Body >
{
  pub x : i64,
  pub h : u32,
  pub a : u8,
  pub f : u16,
  pub w : u32,
  pub body : Body,
}

pub type ObjectHeader = ObjectGeneric< () >;

impl ObjectHeader
{
  pub fn form( self ) -> Object
  {
    let body = ObjectBody { j : 10 };
    Object
    {
      x : self.x,
      h : self.h,
      a : self.a,
      f : self.f,
      w : self.w,
      body,
    }
  }
}

#[ derive( Debug, Clone ) ]
pub struct ObjectBody
{
  pub j : u32,
}

pub type Object = ObjectGeneric< ObjectBody >;

//

impl Borrow< ObjectHeader > for Object
{
  fn borrow<'a>( &'a self ) -> &'a ObjectHeader
  {
    unsafe
    {
      dbg!( &self );
      let result = std::mem::transmute::< &'a Object, &'a ObjectHeader >( self );
      dbg!( &result );
      result
    }
  }
}

//

Output:

[src/main.rs:69] &self = ObjectGeneric {
    x: 1,
    h: 2,
    a: 3,
    f: 4,
    w: 5,
    body: ObjectBody {
        j: 10,
    },
}
[src/main.rs:71] &result = ObjectGeneric {
    x: 1,
    h: 2,
    a: 0,
    f: 10,
    w: 5,
    body: (),
}
[src/main.rs:17] borrowed_header = ObjectGeneric {
    x: 1,
    h: 2,
    a: 0,
    f: 10,
    w: 5,
    body: (),
}

Playground

Upvotes: 1

Views: 251

Answers (1)

dmvict
dmvict

Reputation: 124

In Rust the order of fields in compiled program can be different to order in code. I think in practice compiler reorders fields to reduce padding

You can use directive repr(C) to save original order of fields

#[repr(C)]

Try modified example

===

Official documentation declares that for default layout, the order of fields is not specified :

With the exception of the guarantees provided below, the default layout of structs 
is not specified. 

And, you can read counteropinions for saving layout and some explanation about saving of current behavior.

Also, if directive #[repr(C)] is not used:

  • to test that code incorrectly relies on the layout, use -Z randomize-layout flag. The flag is added by Kixiron, it randomizes the layout of structs.

Upvotes: 2

Related Questions