Is there any difference between the layout of the two?

#[repr(u8)]
enum MyEnum {
    A(u32),
    B(f32, u64),
    C { x: u32, y: u8 },
    D,
 }

vs

#[repr(C, u8)] // `u8` was added
enum MyEnum {
    A(u32),
    B(f32, u64),
    C { x: u32, y: u8 },
    D,
 }

Yes, there is a difference.

The former is the u8 tag followed by 24bit padding so that in each variant the subsequent 32bit value is aligned.

The latter adds 56bit padding after the tag, so that the subsequent payload is 64bit aligned in order to correctly align the payload for the B case. It also adds another 32bit padding after the f32 in case B.

So most notably, one version is 3u64 big, while the other is only 2u64 big.

See all the details of what's going on in the reference

https://doc.rust-lang.org/reference/type-layout.html

Visually:

A, B, C, D for repr u8: Each variant aligns as (discrim, VariantFields)
| 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|
|Ds| pad    |32|32|32|32| pad                   |
|Ds| pad    |32|32|32|32|64|64|64|64|64|64|64|64|
|Ds| pad    |32|32|32|32|u8| pad                |
|Ds| pad                                        |
A, B, C, D for repr C, u8: u8 discrim. followed by union of variants
Each variant aligns as (VariantFields)
| 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|
|Ds| pad                |32|32|32|32| pad                               |
|Ds| pad                |32|32|32|32| pad       |64|64|64|64|64|64|64|64|
|Ds| pad                |32|32|32|32|u8|             pad                |
|Ds| pad                                                                |
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.