Skip to content

Instantly share code, notes, and snippets.

@td-bn
Last active January 11, 2023 12:02
Show Gist options
  • Save td-bn/bec8b756cb3f4ef4f335ace528f5ba4f to your computer and use it in GitHub Desktop.
Save td-bn/bec8b756cb3f4ef4f335ace528f5ba4f to your computer and use it in GitHub Desktop.
Representation of a struct using `repr C`
#[repr(C)]
#[derive(Debug)]
struct Foo {
tiny: bool,
normal: u32,
small: u8,
long: u64,
short: u16,
}
macro_rules! raw_dbg {(
$expr:expr
) => (match $expr { expr => {
eprintln!("{:#?} = {:#x?}", expr, unsafe {
::core::slice::from_raw_parts(
&expr as *const _ as *const ::std::sync::atomic::AtomicU8,
::core::mem::size_of_val(&expr),
)
});
expr
}})}
fn main ()
{
raw_dbg!(
Foo {
tiny: true,
normal: 2,
small: 1,
long: 3,
short: 4,
}
);
}
/*
From: Rust for Rustaceans by Jon Gjengset
First the compiler sees the field tiny, whose logical size is 1 bit (true or false).
But since the CPU and memory operate in terms of bytes, tiny is given 1 byte in the in-memory representation.
Next, normal is a 4-byte type, so we want it to be 4-byte-aligned. But even if Foo is aligned, the 1 byte we allocated
to tiny is going to make normal miss its alignment. To rectify this, the compiler inserts 3 bytes of padding—bytes
with an indeterminate value that are ignored in user code—into the in-memory representation between tiny and normal.
No values go into the padding, but it does take up space.
For the next field, small, alignment is simple: it’s a 1-byte value, and
the current byte offset into the struct is 1 + 3 + 4 = 8.
This is already byte- aligned, so small can go immediately after normal. With long we have a problem again, though.
We are now 1 + 3 + 4 + 1 = 9 bytes into Foo. If Foo is aligned, then long is not 8-byte-aligned the way we want it to be,
so we must insert another 7 bytes of padding to make long aligned again. This also conveniently ensures the 2-byte alignment
we need for the last field, short, bringing the total to 26 bytes. Now that we’ve gone through all the fields, we also need
to determine the alignment of Foo itself. The rule here is to use the largest alignment of any of Foo’s fields, which
will be 8 bytes because of long. So, to ensure that Foo remains aligned if placed in, say, an array, the compiler then
adds a final 6 bytes of padding to make Foo’s size a multiple of its alignment at 32 bytes.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment