Last active
January 11, 2023 12:02
-
-
Save td-bn/bec8b756cb3f4ef4f335ace528f5ba4f to your computer and use it in GitHub Desktop.
Representation of a struct using `repr C`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[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