Ok, so the C
param of the repr()
macro prevents the compiler from reordering fields within a struct for memory-alignment purposes, right? Then, the packed
param disallows the compiler from inserting padding bytes between fields, right?
So, if I was compiling against a hardware target prefers 32-bit-aligned data, and I had 3 versions of the same struct like this:
struct Vertex {
red: u8,
green: u8,
blue: u8,
x: f32,
y: f32,
norm_x: u16,
norm_y: u16,
norm_z: u16,
}
#[repr(C)]
struct CVertex {
red: u8,
green: u8,
blue: u8,
x: f32,
y: f32,
norm_x: u16,
norm_y: u16,
norm_z: u16,
}
#[repr(C, packed)]
struct CPackedVertex {
red: u8,
green: u8,
blue: u8,
x: f32,
y: f32,
norm_x: u16,
norm_y: u16,
norm_z: u16,
}
Each struct is identical, and so it defines 17 bytes of data. Since the hardware wants data 32-bit aligned for best performance, it'll probably reorder Vertex
to something like this maybe?
struct Vertex {
red: u8,
green: u8,
blue: u8,
pad_1: [u8; 1], // pad 1 byte
norm_x: u16,
norm_y: u16,
norm_z: u16,
pad_2: [u8; 2], // padding 2 bytes
x: f32,
y: f32,
} // 20 bytes total
Next is CVertex
:
struct CVertex {
red: u8,
green: u8,
blue: u8,
pad_1: [u8; 1], // pad 1 byte
norm_x: u16,
norm_y: u16,
norm_z: u16,
pad_2: [u8; 2], // pad 2 bytes
x: f32,
y: f32,
} // 20 bytes total
Finally CPackedVertex
:
struct CPackedVertex {
red: u8,
green: u8,
blue: u8,
x: f32,
y: f32,
norm_x: u16,
norm_y: u16,
norm_z: u16,
pad: [u8; 3], // pad 3 bytes
} // 20 bytes total
Does that seem right? I have a little bit of understanding on how compilers might pack and pad data, but it's fuzzy at best. It looks like all structs came out to the same size in this case. I couldn't think of a case where there'd be a deviation from overall size between CVertex
and CPackedVertex
, but I could think of scenarios where those two structs would deviate in size when compared against Vertex
. Am I missing something?