Skip to content

Commit fa11cbd

Browse files
committed
Detail layout of repr(C) unions
1 parent 97cbda4 commit fa11cbd

File tree

1 file changed

+41
-10
lines changed

1 file changed

+41
-10
lines changed

reference/src/layout/unions.md

+41-10
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,6 @@ 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,44 @@ 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+
### Layout of `repr(C)` unions
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+
Since all fields are at offset 0, this implies that `repr(C)` unions do not have
43+
padding before or in-between their fields. They can, however, have trailing
44+
padding (see next example).
45+
46+
Union fields of zero-size participate in the layout computation of the union. For example:
47+
48+
```rust
49+
# use std::mem::{size_of, align_of};
50+
#[repr(C)]
51+
union U {
52+
x: u8,
53+
y: [u16; 0],
54+
}
55+
# fn main() {
56+
// The zero-sized type [u16; 0] raises the alignment requirement 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**: U is larger than its largest field, and has therefore 1 byte of
64+
> trailing padding.
65+
66+
This handling of zero-sized types is equivalent to the handling of zero-sized
67+
types in struct fields, and matches the behavior of GCC and Clang for unions in
68+
C when zero-sized types are allowed via their language extensions.
69+
70+
The bit `i` of a `repr(C)` union is a padding bit if the bit `i` of each of its
71+
fields is a padding bit or trailing padding.

0 commit comments

Comments
 (0)