13
13
union U { f1: T1, f2: T2 }
14
14
```
15
15
16
- is to determine the offset of the fields. The layout of these fields themselves
16
+ is to determine the offset of the fields. The layout of these fields themselves
17
17
is already entirely determined by their types, and since we intend to allow
18
18
creating references to fields (` &u.f1 ` ), unions do not have any wiggle-room
19
19
there.
20
20
21
- ### C-compatible layout ("repr C")
22
-
23
- For unions tagged ` #[repr(C)] ` , the compiler will apply the C layout scheme. Per
24
- sections [ 6.5.8.5] and [ 6.7.2.1.16] of the C11 specification, this means that
25
- the offset of every field is 0. Unsafe code can cast a pointer to the union to
26
- a field type to obtain a pointer to any field, and vice versa.
27
-
28
- [ 6.5.8.5 ] : http://port70.net/~nsz/c/c11/n1570.html#6.5.8p5
29
- [ 6.7.2.1.16 ] : http://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p16
30
-
31
21
### Default layout ("repr rust")
32
22
33
23
** The default layout of unions is not specified.** As of this writing, we want
@@ -38,3 +28,68 @@ contents are.
38
28
Even if the offsets happen to be all 0, there might still be differences in the
39
29
function call ABI. If you need to pass unions by-value across an FFI boundary,
40
30
you have to use ` #[repr(C)] ` .
31
+
32
+ ### C-compatible layout ("repr C")
33
+
34
+ The layout of ` repr(C) ` unions follows the C layout scheme. Per sections
35
+ [ 6.5.8.5] and [ 6.7.2.1.16] of the C11 specification, this means that the offset
36
+ of every field is 0. Unsafe code can cast a pointer to the union to a field type
37
+ to obtain a pointer to any field, and vice versa.
38
+
39
+ [ 6.5.8.5 ] : http://port70.net/~nsz/c/c11/n1570.html#6.5.8p5
40
+ [ 6.7.2.1.16 ] : http://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p16
41
+
42
+ #### Padding
43
+
44
+ Since all fields are at offset 0, ` repr(C) ` unions do not have padding before
45
+ their fields. They can, however, have padding in each union variant * after* the
46
+ field, to make all variants have the same size.
47
+
48
+ Moreover, the entire union can have trailing padding, to make sure the size is a
49
+ multiple of the alignment:
50
+
51
+ ``` rust
52
+ # use std :: mem :: {size_of, align_of};
53
+ #[repr(C , align(2))]
54
+ union U { x : u8 }
55
+ # fn main () {
56
+ // The repr(align) attribute raises the alignment requirement of U to 2
57
+ assert_eq! (align_of :: <U >(), 2 );
58
+ // This introduces trailing padding, raising the union size to 2
59
+ assert_eq! (size_of :: <U >(), 2 );
60
+ # }
61
+ ```
62
+
63
+ > ** Note** : Fields are overlapped instead of laid out sequentially, so
64
+ > unlike structs there is no "between the fields" that could be filled
65
+ > with padding.
66
+
67
+ #### Zero-sized fields
68
+
69
+ ` repr(C) ` union fields of zero-size are handled in the same way as in struct
70
+ fields, matching the behavior of GCC and Clang for unions in C when zero-sized
71
+ types are allowed via their language extensions.
72
+
73
+ That is, these fields occupy zero-size and participate in the layout computation
74
+ of the union as usual:
75
+
76
+ ``` rust
77
+ # use std :: mem :: {size_of, align_of};
78
+ #[repr(C )]
79
+ union U {
80
+ x : u8 ,
81
+ y : [u16 ; 0 ],
82
+ }
83
+ # fn main () {
84
+ // The zero-sized type [u16; 0] raises the alignment requirement to 2
85
+ assert_eq! (align_of :: <U >(), 2 );
86
+ // This in turn introduces trailing padding, raising the union size to 2
87
+ assert_eq! (size_of :: <U >(), 2 );
88
+ # }
89
+ ```
90
+
91
+ ** C++ compatibility hazard** : C++ does, in general, give a size of 1 to types
92
+ with no fields. When such types are used as an union field in C++, a "naive"
93
+ translation of that code into Rust will not produce a compatible result. Refer
94
+ to the [ struct chapter] ( structs-and-tuples.md#c-compatible-layout-repr-c ) for
95
+ further details.
0 commit comments