diff --git a/doc/langref.html.in b/doc/langref.html.in index ac8671ebb7a0..102bc8aeb960 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -1649,6 +1649,7 @@ unwrapped == 1234{#endsyntax#}
- Unlike normal structs, {#syntax#}packed{#endsyntax#} structs have guaranteed in-memory layout: + {#syntax#}packed{#endsyntax#} structs, like {#syntax#}enum{#endsyntax#}, are based on the concept + of interpreting integers differently. All packed structs have a backing integer, + which is implicitly determined by the total bit count of fields, or explicitly specified. + Packed structs have well-defined memory layout - exactly the same ABI as their backing integer. +
++ Each field of a packed struct is interpreted as a logical sequence of bits, arranged from + least to most significant. Allowed field types:
This means that a {#syntax#}packed struct{#endsyntax#} can participate @@ -2245,10 +2250,11 @@ or This even works at {#link|comptime#}:
{#code|test_packed_structs.zig#} -- The backing integer is inferred from the fields' total bit width. - Optionally, it can be explicitly provided and enforced at compile time: + The backing integer can be inferred or explicitly provided. When + inferred, it will be unsigned. When explicitly provided, its bit width + will be enforced at compile time to exactly match the total bit width of + the fields:
{#code|test_missized_packed_struct.zig#} @@ -2290,18 +2296,18 @@ orEquating packed structs results in a comparison of the backing integer, - and only works for the `==` and `!=` operators. + and only works for the {#syntax#}=={#endsyntax#} and {#syntax#}!={#endsyntax#} {#link|Operators#}.
{#code|test_packed_struct_equality.zig#}- Using packed structs with {#link|volatile#} is problematic, and may be a compile error in the future. - For details on this subscribe to - this issue. - TODO update these docs with a recommendation on how to use packed structs with MMIO - (the use case for volatile packed structs) once this issue is resolved. - Don't worry, there will be a good solution for this use case in zig. + Field access and assignment can be understood as shorthand for bitshifts + on the backing integer. These operations are not {#link|atomic|Atomics#}, + so beware using field access syntax when combined with memory-mapped + input-output (MMIO). Instead of field access on {#link|volatile#} {#link|Pointers#}, + construct a fully-formed new value first, then write that value to the volatile pointer.
+ {#code|packed_struct_mmio.zig#} {#header_close#} {#header_open|Struct Naming#} diff --git a/doc/langref/packed_struct_mmio.zig b/doc/langref/packed_struct_mmio.zig new file mode 100644 index 000000000000..18b57f83b2eb --- /dev/null +++ b/doc/langref/packed_struct_mmio.zig @@ -0,0 +1,19 @@ +pub const GpioRegister = packed struct(u8) { + GPIO0: bool, + GPIO1: bool, + GPIO2: bool, + GPIO3: bool, + reserved: u4 = 0, +}; + +const gpio: *volatile GpioRegister = @ptrFromInt(0x0123); + +pub fn writeToGpio(new_states: GpioRegister) void { + // Example of what not to do: + // BAD! gpio.GPIO0 = true; BAD! + + // Instead, do this: + gpio.* = new_states; +} + +// syntax