Skip to content

Commit a9223e2

Browse files
committed
say more about zero-sized things
1 parent 17dab33 commit a9223e2

File tree

1 file changed

+32
-8
lines changed

1 file changed

+32
-8
lines changed

Diff for: reference/src/representation/structs-and-tuples.md

+32-8
Original file line numberDiff line numberDiff line change
@@ -188,14 +188,6 @@ following:
188188

189189
[^aligned]: Aligning an offset O to an alignment A means to round up the offset O until it is a multiple of the alignment A.
190190

191-
One deviation from C comes about with "empty structs". In Rust, a
192-
struct that contains (transitively) no data members is considered to
193-
have size zero, which is not something that exists in C. This includes
194-
a struct like `#[repr(C)] struct Foo { }`. Further, when a
195-
`#[repr(C)]` struct has a field whose type has zero-size, that field
196-
may induce padding due to its alignment, but will not otherwise affect
197-
the offsets of subsequent fields (as it takes up zero space).
198-
199191
The intention is that if one has a set of C struct declarations and a
200192
corresponding set of Rust struct declarations, all of which are tagged
201193
with `#[repr(C)]`, then the layout of those structs will all be
@@ -207,6 +199,38 @@ their layout in a C program.
207199

208200
See also the notes on [ABI compatibility](#fnabi) under the section on `#[repr(transparent)]`.
209201

202+
**Structs with no fields.** One area where Rust layout can deviate
203+
from C/C++ -- even with `#[repr(C)]` -- comes about with "empty
204+
structs" that have no fields. In C, an empty struct declaration like
205+
`struct Foo { }` is illegal. However, both gcc and clang support
206+
options to enable such structs, and [assign them size
207+
zero](https://godbolt.org/z/AS2gdC). Rust behaves the same way --
208+
empty structs have size 0 and alignment 1 (unless an explicit
209+
`#[repr(align)]` is present). C++, in contrast, gives empty structs a
210+
size of 1, unless they are inherited from or they are fields that have
211+
the `[[no_unique_address]]` attribute, in which case they do not
212+
increase the overall size of the struct.
213+
214+
**Structs of zero-size.** It is also possible to have structs that
215+
have fields but have non-zero size. In this case, the size of the
216+
struct would be zero, but its alignment may be greater. For example,
217+
`#[repr(C)] struct Foo { x: [u16; 0] }` would have an alignment of 2
218+
bytes by default. ([This matches the behavior in gcc and
219+
clang](https://godbolt.org/z/5w0gkq).)
220+
221+
**Structs with fields of zero-size.** If a `#[repr(C)]` struct
222+
containing a field of zero-size, that field does not occupy space in
223+
the struct; it can affect the offsets of subsequent fields if it
224+
induces padding due to the alignment on its type. ([This matches the
225+
behavior in gcc and clang](https://godbolt.org/z/5w0gkq).)
226+
227+
**C++ compatibility hazard.** As noted above when discussing structs
228+
with no fields, C++ treats empty structs like `struct Foo { }`
229+
differently from C and Rust. This can introduce subtle compatibility
230+
hazards. If you have an empty struct in your C++ code and you make the
231+
"naive" translation into Rust, even tagging with `#[repr(C)]` will not
232+
produce layout- or ABI-compatible results.
233+
210234
### Fixed alignment
211235

212236
The `#[repr(align(N))]` attribute may be used to raise the alignment

0 commit comments

Comments
 (0)