Array types, [T; N]
, store N
values of type T
with a constant stride.
Here, stride is the distance between each pair of consecutive values within
the array.
The offset of the first array element is 0
, that is, a pointer to the array
and a pointer to its first element both point to the same memory address.
The alignment of array types is greater or equal to the alignment of its
element type. If the element type is repr(C)
the size and alignment of the
array is guaranteed to be the same as the size and alignment of a C array with
the same element type.
Note: the type of array arguments in C function signatures, e.g.,
void foo(T x[N])
, decays to a pointer. That is, these functions do not take arrays as an arguments, they take a pointer to the first element of the array instead. Array types are therefore improper C types (not C FFI safe) in Rust foreign function declarations, e.g.,extern { fn foo(x: [T; N]) -> [U; M]; }
. Pointers to arrays are fine:extern { fn foo(x: *const [T; N]) -> *const [U; M]; }
, andstruct
s andunion
s containing arrays are also fine.
The stride of the array is constant for all element pairs and it is computed as the size of the element type rounded up to the next multiple of the alignment of the element type.
When the element size is a multiple of the element's alignment, then stride == size
, and the elements are laid out contiguously in memory, e.g., [u8; 4]
.
In this case, the size of the array can be computed as size_of::<T>() * N
,
and a pointer to the i
-th element of the array can be obtained by offsetting a
pointer to the first element of the array by i
1.
Note: In the current Rust implementation, size is always a multiple of the element's alignment, and therefore
stride == size
always holds. This is, however, not guaranteed by the layout of structs and tuples.
The layout of packed SIMD vector types 2 requires the size and alignment of the vector elements to match. That is, types with packed SIMD vector layout are layout compatible with arrays having the same element type and the same number of elements as the vector.
The layout of a slice [T]
of length N
is the same as that of a [T; N]
array.
Currently, the layout of structs and tuples does not guarantee that the element size is a multiple of its alignment. For example, consider:
struct A(u16, u8);
type B = [A; 4];
In the current Rust implementation, A
has an alignment and a size of 4
, and
B
has a size of 16
, such that B
contains four A
s that are contiguously
laid in memory.
However, a future Rust implementation could implement a layout optimization that
reduces the size of A
to 3
. For the elements of B
to be properly aligned,
B
would need to choose a stride == 4
, resulting in a stride > size
.
Guaranteeing stride >= size
is forward-compatible with such
layout-optimization proposals:
- rust-lang/rfcs/1397: Spearate size and stride for types
- rust-lang/rust/17027: Collapse trailing padding
Footnotes
-
When
stride > size
the pointer needs to be advanced by the array stride instead of by the element size. ↩ -
The packed SIMD vector layout is the layout of
repr(simd)
types like__m128
. ↩