4

I tried this on 64bit Linux and it gives 16:

println!("Results: {}", mem::size_of::<Option<f64>>())

as I understand, this is because of:

pub struct Discriminant<T>(u64, PhantomData<fn() -> T>);

What is the sense in a 64bit discriminant? For code written by hand, 256 will be enough, for generated code 2^16 would be a huge number, and I can not even imagine why need 2^32. Why would it use 64 bits for this?

Why does the compiler not optimize it for the Option case? 8 bits at the end of the structure should be enough.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
user1244932
  • 7,352
  • 5
  • 46
  • 103
  • 1
    *Why does the compiler not optimize it for the `Option` case* — it **does** optimize it. You just don't yet understand that is optimizing for speed, not memory space. – Shepmaster Mar 03 '18 at 20:47
  • See also [Why does an enum require extra memory size?](https://stackoverflow.com/q/27324821/155423), where a comment addresses your concern. – Shepmaster Mar 03 '18 at 20:52
  • 1
    Note that the definition of `Discriminant` uses `u64` not because all discriminants are a `u64`, but because it takes a `u64` to store the largest possible discriminant value. In an `Option`, the size of the discriminant is just 1 (i.e. the size of an `u8`). – Francis Gagné Mar 03 '18 at 21:30
  • And in `Option<&T>` and `Option – CodesInChaos Mar 03 '18 at 22:03

1 Answers1

8

f64 has a 64-bit alignment. Thus a type containing an f64 needs an alignment of at least 64 bits. The size of a type is guaranteed to be a multiple of its alignment. Since it can't fit in 64 bits, it needs to go up to the next multiple, 128 bits/16 bytes.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • *The size of a type is guaranteed to be a multiple of its alignment* — I don't believe this is strictly true; you can opt into different methods of packing a struct and what is valid varies depends on architecture. I'm not sure if an enum has options for controlling packing though. – Shepmaster Mar 03 '18 at 21:02
  • @Shepmaster "More specifically, this is the offset in bytes between successive elements in an array with that item type including alignment padding" implies that it's a multiple, because otherwise the second struct in an array would be unaligned. – CodesInChaos Mar 03 '18 at 21:25
  • `std::mem::align_of` != `std::mem::size_of`. A single value in a struct or on the stack may have some additional fields packed into its alignment padding. – the8472 Mar 03 '18 at 22:05
  • @the8472 But `std::mem::size_of::() % std::mem::align_of::() == 0` for all types, right? – CodesInChaos Mar 03 '18 at 22:30
  • Ah right, I was thinking of the [proposal to distinguish stride and alignment size](https://github.com/rust-lang/rfcs/issues/1397), but that's not even an RFC yet. – the8472 Mar 04 '18 at 17:06