Skip to content

Commit 727fc88

Browse files
authored
Merge pull request #160 from gnzlbg/reprc_unions
Detail layout of repr(C) unions
2 parents 003eee9 + ef65895 commit 727fc88

File tree

1 file changed

+66
-11
lines changed

1 file changed

+66
-11
lines changed

Diff for: reference/src/layout/unions.md

+66-11
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,11 @@ like
1313
union U { f1: T1, f2: T2 }
1414
```
1515

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
1717
is already entirely determined by their types, and since we intend to allow
1818
creating references to fields (`&u.f1`), unions do not have any wiggle-room
1919
there.
2020

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-
3121
### Default layout ("repr rust")
3222

3323
**The default layout of unions is not specified.** As of this writing, we want
@@ -38,3 +28,68 @@ contents are.
3828
Even if the offsets happen to be all 0, there might still be differences in the
3929
function call ABI. If you need to pass unions by-value across an FFI boundary,
4030
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

Comments
 (0)