1
1
# Type Layout
2
2
3
- The layout of a type is the way the size, alignment, and the offsets of any
4
- fields and discriminants for the values of that type.
3
+ The layout of a type is its size, alignment, and the relative offsets of its
4
+ fields. For enums, how the discriminant is laid out and interpreted is also part
5
+ of type layout.
5
6
6
- While specific releases of the compiler will have the same layout for types,
7
- there is a lot of room for new versions of the compiler to do different things.
8
- Instead of trying to document exactly what is done, we only document what is
9
- guaranteed today.
7
+ Type layout can be changed with each compilation. Instead of trying to document
8
+ exactly what is done, we only document what is guaranteed today.
10
9
11
10
## Size and Alignment
12
11
@@ -37,7 +36,6 @@ The size of most primitives is given in this table.
37
36
38
37
Type | ` size_of::\<Type>() `
39
38
- | - | -
40
- bool | 1
41
39
u8 | 1
42
40
u16 | 2
43
41
u32 | 4
@@ -55,7 +53,7 @@ target platform. For example, on a 32 bit target, this is 4 bytes and on a 64
55
53
bit target, this is 8 bytes.
56
54
57
55
Most primitives are generally aligned to their size, although this is
58
- platform-specific behavior. In particular, on x86 u64 and f64 may be only
56
+ platform-specific behavior. In particular, on x86 u64 and f64 are only
59
57
aligned to 32 bits.
60
58
61
59
## Pointers and References Layout
@@ -82,6 +80,9 @@ has a size of `size_of::<T>() * n` and the same alignment of `T`.
82
80
83
81
Slices have the same layout as the section of the array they slice.
84
82
83
+ > Note: This is about the raw ` [T] ` type, not pointers (` &[T] ` , ` Box<[T]> ` ,
84
+ > etc.) to slices.
85
+
85
86
## Tuple Layout
86
87
87
88
Tuples do not have any guarantes about their layout.
@@ -93,6 +94,9 @@ zero-sized type to have a size of 0 and an alignment of 1.
93
94
94
95
Trait objects have the same layout as the value the trait object is of.
95
96
97
+ > Note: This is about the raw trait object types, not pointers (` &Trait ` ,
98
+ > ` Box<Trait> ` , etc.) to trait objects.
99
+
96
100
## Closure Layout
97
101
98
102
Closures have no layout guarantees.
@@ -102,9 +106,6 @@ Closures have no layout guarantees.
102
106
All user-defined composite types (` struct ` s, ` enum ` , and ` union ` s) have a
103
107
* representation* that specifies what the layout is for the type.
104
108
105
- > Note: The representation does not depend upon the type's fields or generic
106
- > parameters.
107
-
108
109
The possible representations for a type are the default representation, ` C ` , the
109
110
primitive representations, and ` packed ` . Multiple representations can be applied
110
111
to a single type.
@@ -121,6 +122,11 @@ struct ThreeInts {
121
122
}
122
123
```
123
124
125
+ > Note: As a consequence of the representation being an attribute on the item,
126
+ > the representation does not depend on generic parameters. Any two types with
127
+ > the same name have the same representation. For example, ` Foo<Bar> ` and
128
+ > ` Foo<Baz> ` both have the same representation.
129
+
124
130
The representation of a type does not change the layout of its fields. For
125
131
example, a struct with a ` C ` representation that contains a struct ` Inner ` with
126
132
the default representation will not change the layout of Inner.
@@ -134,39 +140,63 @@ There are no guarantees of data layout made by this representation.
134
140
135
141
### The ` C ` Representation
136
142
137
- The ` C ` representation is designed for creating types that are interoptable with
138
- the C Language and soundly performing operations that rely on data layout such
139
- as reinterpreting values as a different type.
143
+ The ` C ` representation is designed for dual purposes. One purpose is for
144
+ creating types that are interoptable with the C Language. The second purpose is
145
+ to create types that you can soundly performing operations that rely on data
146
+ layout such as reinterpreting values as a different type.
147
+
148
+ Because of this dual purpose, it is possible to create types that are not useful
149
+ for interfacing with the C programming language.
140
150
141
151
This representation can be applied to structs, unions, and enums.
142
152
143
153
#### \# [ repr(C)] Structs
144
154
145
155
The alignment of the struct is the alignment of the most-aligned field in it.
146
156
147
- The size and offset of fields is determine by the following algorithm.
157
+ The size and offset of fields is determined by the following algorithm.
148
158
149
159
Start with a current offset of 0 bytes.
150
160
151
161
For each field in declaration order in the struct, first determine the size and
152
162
alignment of the field. If the current offset is not a multiple of the field's
153
- alignment, then add padding bytes increasing the current offset until the
154
- current offset is a multiple of the field's alignment. The offset for the field
155
- is what the current offset is now. Then increase the current offset by the size
156
- of the field.
163
+ alignment, then add padding bytes to the current offset until it is a multiple
164
+ of the field's alignment. The offset for the field is what the current offset
165
+ is now. Then increase the current offset by the size of the field.
157
166
158
167
Finally, the size of the struct is the current offset rounded up to the nearest
159
168
multiple of the struct's alignment.
160
169
170
+ Here is this algorithm described in psudeocode.
171
+
172
+ ``` rust,ignore
173
+ struct.alignment = struct.fields().map(|field| field.alignment).max();
174
+
175
+ let current_offset = 0;
176
+
177
+ for field in struct.fields_in_declaration_order() {
178
+ // Increase the current offset so that it's a multiple of the alignment
179
+ // of this field. For the first field, this will always be zero.
180
+ // The skipped bytes are called padding bytes.
181
+ current_offset += field.alignment % current_offset;
182
+
183
+ struct[field].offset = current_offset;
184
+
185
+ current_offset += field.size;
186
+ }
187
+
188
+ struct.size = current_offset + current_offset % struct.alignment;
189
+ ```
190
+
161
191
> Note: You can have zero-sized structs from this algorithm. This differs from
162
192
> C where structs without data still have a size of one byte.
163
193
164
194
#### \# [ repr(C)] Unions
165
195
166
196
A union declared with ` #[repr(C)] ` will have the same size and alignment as an
167
197
equivalent C union declaration in the C language for the target platform.
168
- Usually, a union would have the maximum size of the maximum size of all of its
169
- fields , and the maximum alignment of the maximum alignment of all of its fields.
198
+ The union will have a size of the maximum size of all of its fields rounded to
199
+ its alignment , and an alignment of the maximum alignment of all of its fields.
170
200
These maximums may come from different fields.
171
201
172
202
```
@@ -178,6 +208,17 @@ union Union {
178
208
179
209
assert_eq!(std::mem::size_of::<Union>(), 4); // From f2
180
210
assert_eq!(std::mem::align_of::<Union>(), 2); // From f1
211
+
212
+ #[repr(C)]
213
+ union SizeRoundedUp {
214
+ a: u32,
215
+ b: [u16; 3],
216
+ }
217
+
218
+ assert_eq!(std::mem::size_of::<SizeRoundedUp>(), 8); // Size of 6 from b,
219
+ // rounded up to 8 from
220
+ // alignment of a.
221
+ assert_eq!(std::mem::align_of::<SizeRoundedUp>(), 4); // From a
181
222
```
182
223
183
224
#### \# [ repr(C)] Enums
@@ -201,6 +242,9 @@ It is an error for [zero-variant enumerations] to have the `C` representation.
201
242
202
243
For all other enumerations, the layout is unspecified.
203
244
245
+ Likewise, combining the ` C ` representation with a primitive representation, the
246
+ layout is unspecified.
247
+
204
248
### Primitive representations
205
249
206
250
The * primitive representations* are the representations with the same names as
@@ -218,14 +262,16 @@ representation.
218
262
219
263
For all other enumerations, the layout is unspecified.
220
264
265
+ Likewise, combining two primitive representations together is unspecified.
266
+
221
267
### The ` packed ` Representation
222
268
223
269
The ` packed ` representation can only be used on ` struct ` s and ` union ` s.
224
270
225
271
It modifies the representation (either the default or ` C ` ) by removing any
226
272
padding bytes and forcing the alignment of the type to ` 1 ` .
227
273
228
- > Warning: Dereferencing an unaligned pointer is [ undefined behaviour] and is
274
+ > Warning: Dereferencing an unaligned pointer is [ undefined behaviour] and it is
229
275
> possible to [ safely create unaligned pointers to ` packed ` fields] [ 27060 ] .
230
276
> Like all ways to create undefined behavior in safe Rust, this is a bug.
231
277
0 commit comments