about summary refs log tree commit diff
diff options
context:
space:
mode:
authorHavvy <ryan.havvy@gmail.com>2017-09-26 17:41:21 -0700
committerHavvy <ryan.havvy@gmail.com>2017-09-27 23:01:48 -0700
commit01183982911a761bab1e2c6793d0ee9fdf651270 (patch)
tree31858352efe8e480409d59ff2f0e492124d4c173
parent1c4510adc81bd7623bc2993b42ee7d87320f1f2b (diff)
downloadrust-01183982911a761bab1e2c6793d0ee9fdf651270.tar.gz
rust-01183982911a761bab1e2c6793d0ee9fdf651270.zip
Docs for size_of::<#[repr(C)]> items.
Most of this info comes from camlorn's blog post on optimizing
struct layout and the Rustonomicon.
-rw-r--r--src/libcore/mem.rs78
1 files changed, 78 insertions, 0 deletions
diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs
index 669b93120cf..56685a67ad5 100644
--- a/src/libcore/mem.rs
+++ b/src/libcore/mem.rs
@@ -209,6 +209,35 @@ pub fn forget<T>(t: T) {
 /// The mutability of a pointer does not change its size. As such, `&T` and `&mut T`
 /// have the same size. Likewise for `*const T` and `*mut T`.
 ///
+/// # Size of #[repr(C)] items
+///
+/// The `C` representation for items has a defined layout. With this layout,
+/// the size of items is also stable as long as all fields have a stable size.
+///
+/// ## Structs
+///
+/// For `structs`, the size is determined by the following algorithm.
+///
+/// For each field in the struct ordered by declaration order:
+///
+/// 1. Add the size of the field.
+/// 2. Round up the current size to the nearest multiple of the next field's [alignment].
+///
+/// Finally, round the size of the struct to the nearest multiple of its [alignment].
+///
+/// Unlike `C`, zero sized structs are not rounded up to one byte in size.
+///
+/// ## Enums
+///
+/// Enums that carry no data other than the descriminant have the same size as C enums
+/// on the platform they are compiled for.
+///
+/// ## Unions
+///
+/// The size of a union is the size of its largest field.
+///
+/// Unlike `C`, zero sized unions are not rounded up to one byte in size.
+///
 /// # Examples
 ///
 /// ```
@@ -231,6 +260,55 @@ pub fn forget<T>(t: T) {
 /// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<Option<&i32>>());
 /// assert_eq!(mem::size_of::<Box<i32>>(), mem::size_of::<Option<Box<i32>>>());
 /// ```
+///
+/// Using `#[repr(C)]`.
+///
+/// ```
+/// use std::mem;
+///
+/// #[repr(C)]
+/// struct FieldStruct {
+///     first: u8,
+///     second: u16,
+///     third: u8
+/// }
+///
+/// // The size of the first field is 1, so add 1 to the size. Size is 1.
+/// // The alignment of the second field is 2, so add 1 to the size for padding. Size is 2.
+/// // The size of the second field is 2, so add 2 to the size. Size is 4.
+/// // The alignment of the third field is 1, so add 0 to the size for padding. Size is 4.
+/// // The size of the third field is 1, so add 1 to the size. Size is 5.
+/// // Finally, the alignment of the struct is 2, so add 1 to the size for padding. Size is 6.
+/// assert_eq!(6, mem::size_of::<FieldStruct>());
+///
+/// #[repr(C)]
+/// struct TupleStruct(u8, u16, u8);
+///
+/// // Tuple structs follow the same rules.
+/// assert_eq!(6, mem::size_of::<TupleStruct>());
+///
+/// // Note that reordering the fields can lower the size. We can remove both padding bytes
+/// // by putting `third` before `second`.
+/// #[repr(C)]
+/// struct FieldStructOptimized {
+///     first: u8,
+///     third: u8,
+///     second: u16
+/// }
+///
+/// assert_eq!(4, mem::size_of::<FieldStructOptimized>());
+///
+/// // Union size is the size of the largest field.
+/// #[repr(C)]
+/// union ExampleUnion {
+///     smaller: u8,
+///     larger: u16
+/// }
+///
+/// assert_eq!(2, mem::size_of::<ExampleUnion>());
+/// ```
+///
+/// [alignment]: ./fn.align_of.html
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_size_of"))]