authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-04-11 14:16:57-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-04-15 19:19:23-07:00
logbd38c417fc9ba367b3cfcd49d29b52412ef04251
tree0e7df5a25d1706e050ef806ef97be69f0a4c553f
parenta8621731ec9726288614c8c1b88ae8293ebbf606

langref: reword some packed struct text and example


2 files changed, 34 insertions(+), 30 deletions(-)

doc/langref.html.in+24-23
...@@ -1649,6 +1649,7 @@ unwrapped == 1234{#endsyntax#}</pre>...@@ -1649,6 +1649,7 @@ unwrapped == 1234{#endsyntax#}</pre>
1649 <li>{#link|Floats#}</li>1649 <li>{#link|Floats#}</li>
1650 <li>{#link|bool|Primitive Types#}</li>1650 <li>{#link|bool|Primitive Types#}</li>
1651 <li>{#link|type|Primitive Types#}</li>1651 <li>{#link|type|Primitive Types#}</li>
1652 <li>{#link|packed struct#}</li>
1652 </ul>1653 </ul>
1653 </td>1654 </td>
1654 <td>1655 <td>
...@@ -2224,27 +2225,24 @@ or...@@ -2224,27 +2225,24 @@ or
22242225
2225 {#header_open|packed struct#}2226 {#header_open|packed struct#}
2226 <p>2227 <p>
2227 Unlike normal structs, {#syntax#}packed{#endsyntax#} structs have guaranteed in-memory layout:2228 {#syntax#}packed{#endsyntax#} structs, like {#syntax#}enum{#endsyntax#}, are based on the concept
2229 of interpreting integers differently. All packed structs have a <strong>backing integer</strong>,
2230 which is implicitly determined by the total bit count of fields, or explicitly specified.
2231 Packed structs have well-defined memory layout - exactly the same ABI as their backing integer.
2232 </p>
2233 <p>
2234 Each field of a packed struct is interpreted as a logical sequence of bits, arranged from
2235 least to most significant. Allowed field types:
2228 </p>2236 </p>
2229 <ul>2237 <ul>
2230 <li>Fields are arranged in the order declared, from the least to the most significant bits of a backing integer.</li>2238 <li>An {#link|integer|Integers#} field uses exactly as many bits as its
2231 <li>There is no padding between fields.</li>2239 bit width. For example, a {#syntax#}u5{#endsyntax#} will use 5 bits of
2232 <li>The backing integer has the same bit width as the fields' total bit width.</li>2240 the backing integer.</li>
2233 <li>The backing integer is subject to the same rules as any integer, including {#link|alignment|Alignment#},
2234 having a maximum bit count of 65535, and the host endianness.
2235 On a big endian system, the first declared field will have the highest memory address, and on a little endian system, the lowest.
2236 </li>
2237 <li>Due to {#link|alignment|Alignment#}, the backing integer may require more memory that its bit width. {#link|@bitSizeOf|@bitSizeOf#} and {#link|@sizeOf|@sizeOf#} can interrogate the difference.</li>
2238 <li>Field access and assignment can be understood as shorthand for bitshifts on the backing integer.</li>
2239 <li>An {#link|integer|Integers#} field uses exactly as many bits as its bit width. For example, a {#syntax#}u5{#endsyntax#} will use 5 bits of the backing integer.</li>
2240 <li>A {#link|bool|Primitive Types#} field uses exactly 1 bit.</li>2241 <li>A {#link|bool|Primitive Types#} field uses exactly 1 bit.</li>
2241 <li>An {#link|enum#} field uses exactly the bit width of its integer tag type.</li>2242 <li>An {#link|enum#} field uses exactly the bit width of its integer tag type.</li>
2242 <li>A {#link|packed union#} field uses exactly the bit width of the union field with2243 <li>A {#link|packed union#} field uses exactly the bit width of the union field with
2243 the largest bit width.</li>2244 the largest bit width.</li>
2244 <li>A {#syntax#}packed struct{#endsyntax#} field, when within a {#syntax#}packed struct{#endsyntax#}, uses exactly the bit width of its backing integer. For example,2245 <li>A {#syntax#}packed struct{#endsyntax#} field uses the bits of its backing integer.</li>
2245 a {#syntax#}packed struct{#endsyntax#} field having backing integer {#syntax#}u17{#endsyntax#} uses 17 bits of its parent's backing integer.
2246 </li>
2247 <li>Packed structs support equality operators.</li>
2248 </ul>2246 </ul>
2249 <p>2247 <p>
2250 This means that a {#syntax#}packed struct{#endsyntax#} can participate2248 This means that a {#syntax#}packed struct{#endsyntax#} can participate
...@@ -2252,9 +2250,11 @@ or...@@ -2252,9 +2250,11 @@ or
2252 This even works at {#link|comptime#}:2250 This even works at {#link|comptime#}:
2253 </p>2251 </p>
2254 {#code|test_packed_structs.zig#}2252 {#code|test_packed_structs.zig#}
2255
2256 <p>2253 <p>
2257 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:2254 The backing integer can be inferred or explicitly provided. When
2255 inferred, it will be unsigned. When explicitly provided, its bit width
2256 will be enforced at compile time to exactly match the total bit width of
2257 the fields:
2258 </p>2258 </p>
2259 {#code|test_missized_packed_struct.zig#}2259 {#code|test_missized_packed_struct.zig#}
22602260
...@@ -2296,17 +2296,18 @@ or...@@ -2296,17 +2296,18 @@ or
22962296
2297 <p>2297 <p>
2298 Equating packed structs results in a comparison of the backing integer, 2298 Equating packed structs results in a comparison of the backing integer,
2299 and only works for the `==` and `!=` operators.2299 and only works for the {#syntax#}=={#endsyntax#} and {#syntax#}!={#endsyntax#} {#link|Operators#}.
2300 </p>2300 </p>
2301 {#code|test_packed_struct_equality.zig#}2301 {#code|test_packed_struct_equality.zig#}
23022302
2303 <p>2303 <p>
2304 Packed structs can be used to interact with memory-mapped input-output (MMIO), which is2304 Field access and assignment can be understood as shorthand for bitshifts
2305 common in embedded applications. A pointer of the correct alignment and address to a packed struct2305 on the backing integer. These operations are not {#link|atomic|Atomics#},
2306 can be constructed to faciltiate manipulation of bit-packed registers without arduous bitshifting.2306 so beware using field access syntax when combined with memory-mapped
2307 2307 input-output (MMIO). Instead of field access on {#link|volatile#} {#link|Pointers#},
2308 {#code|packed_struct_mmio.zig#}2308 construct a fully-formed new value first, then write that value to the volatile pointer.
2309 </p>2309 </p>
2310 {#code|packed_struct_mmio.zig#}
2310 {#header_close#}2311 {#header_close#}
23112312
2312 {#header_open|Struct Naming#}2313 {#header_open|Struct Naming#}
doc/langref/packed_struct_mmio.zig+10-7
...@@ -1,16 +1,19 @@...@@ -1,16 +1,19 @@
1pub const GPIORegister = packed struct(u8) {1pub const GpioRegister = packed struct(u8) {
2 GPIO0: bool,2 GPIO0: bool,
3 GPIO1: bool,3 GPIO1: bool,
4 GPIO2: bool,4 GPIO2: bool,
5 GPIO3: bool,5 GPIO3: bool,
6 _reserved: u4 = 0,6 reserved: u4 = 0,
7};7};
88
9/// Write a new state to the memory-mapped IO.9const gpio: *volatile GpioRegister = @ptrFromInt(0x0123);
10pub fn writeToGPIO(new_states: GPIORegister) void {10
11 const gpio_register_address = 0x0123;11pub fn writeToGpio(new_states: GpioRegister) void {
12 const raw_ptr: *align(1) volatile GPIORegister = @ptrFromInt(gpio_register_address);12 // Example of what not to do:
13 raw_ptr.* = new_states;13 // BAD! gpio.GPIO0 = true; BAD!
14
15 // Instead, do this:
16 gpio.* = new_states;
14}17}
1518
16// syntax19// syntax