mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
langref: reword some packed struct text and example
This commit is contained in:
parent
a8621731ec
commit
bd38c417fc
@ -1649,6 +1649,7 @@ unwrapped == 1234{#endsyntax#}</pre>
|
|||||||
<li>{#link|Floats#}</li>
|
<li>{#link|Floats#}</li>
|
||||||
<li>{#link|bool|Primitive Types#}</li>
|
<li>{#link|bool|Primitive Types#}</li>
|
||||||
<li>{#link|type|Primitive Types#}</li>
|
<li>{#link|type|Primitive Types#}</li>
|
||||||
|
<li>{#link|packed struct#}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@ -2224,27 +2225,24 @@ or
|
|||||||
|
|
||||||
{#header_open|packed struct#}
|
{#header_open|packed struct#}
|
||||||
<p>
|
<p>
|
||||||
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 <strong>backing integer</strong>,
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Each field of a packed struct is interpreted as a logical sequence of bits, arranged from
|
||||||
|
least to most significant. Allowed field types:
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Fields are arranged in the order declared, from the least to the most significant bits of a backing integer.</li>
|
<li>An {#link|integer|Integers#} field uses exactly as many bits as its
|
||||||
<li>There is no padding between fields.</li>
|
bit width. For example, a {#syntax#}u5{#endsyntax#} will use 5 bits of
|
||||||
<li>The backing integer has the same bit width as the fields' total bit width.</li>
|
the backing integer.</li>
|
||||||
<li>The backing integer is subject to the same rules as any integer, including {#link|alignment|Alignment#},
|
|
||||||
having a maximum bit count of 65535, and the host endianness.
|
|
||||||
On a big endian system, the first declared field will have the highest memory address, and on a little endian system, the lowest.
|
|
||||||
</li>
|
|
||||||
<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>
|
|
||||||
<li>Field access and assignment can be understood as shorthand for bitshifts on the backing integer.</li>
|
|
||||||
<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>
|
|
||||||
<li>A {#link|bool|Primitive Types#} field uses exactly 1 bit.</li>
|
<li>A {#link|bool|Primitive Types#} field uses exactly 1 bit.</li>
|
||||||
<li>An {#link|enum#} field uses exactly the bit width of its integer tag type.</li>
|
<li>An {#link|enum#} field uses exactly the bit width of its integer tag type.</li>
|
||||||
<li>A {#link|packed union#} field uses exactly the bit width of the union field with
|
<li>A {#link|packed union#} field uses exactly the bit width of the union field with
|
||||||
the largest bit width.</li>
|
the largest bit width.</li>
|
||||||
<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,
|
<li>A {#syntax#}packed struct{#endsyntax#} field uses the bits of its backing integer.</li>
|
||||||
a {#syntax#}packed struct{#endsyntax#} field having backing integer {#syntax#}u17{#endsyntax#} uses 17 bits of its parent's backing integer.
|
|
||||||
</li>
|
|
||||||
<li>Packed structs support equality operators.</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
<p>
|
<p>
|
||||||
This means that a {#syntax#}packed struct{#endsyntax#} can participate
|
This means that a {#syntax#}packed struct{#endsyntax#} can participate
|
||||||
@ -2252,9 +2250,11 @@ or
|
|||||||
This even works at {#link|comptime#}:
|
This even works at {#link|comptime#}:
|
||||||
</p>
|
</p>
|
||||||
{#code|test_packed_structs.zig#}
|
{#code|test_packed_structs.zig#}
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
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:
|
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:
|
||||||
</p>
|
</p>
|
||||||
{#code|test_missized_packed_struct.zig#}
|
{#code|test_missized_packed_struct.zig#}
|
||||||
|
|
||||||
@ -2296,17 +2296,18 @@ or
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
Equating packed structs results in a comparison of the backing integer,
|
Equating 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#}.
|
||||||
</p>
|
</p>
|
||||||
{#code|test_packed_struct_equality.zig#}
|
{#code|test_packed_struct_equality.zig#}
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Packed structs can be used to interact with memory-mapped input-output (MMIO), which is
|
Field access and assignment can be understood as shorthand for bitshifts
|
||||||
common in embedded applications. A pointer of the correct alignment and address to a packed struct
|
on the backing integer. These operations are not {#link|atomic|Atomics#},
|
||||||
can be constructed to faciltiate manipulation of bit-packed registers without arduous bitshifting.
|
so beware using field access syntax when combined with memory-mapped
|
||||||
|
input-output (MMIO). Instead of field access on {#link|volatile#} {#link|Pointers#},
|
||||||
{#code|packed_struct_mmio.zig#}
|
construct a fully-formed new value first, then write that value to the volatile pointer.
|
||||||
</p>
|
</p>
|
||||||
|
{#code|packed_struct_mmio.zig#}
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|Struct Naming#}
|
{#header_open|Struct Naming#}
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
pub const GPIORegister = packed struct(u8) {
|
pub const GpioRegister = packed struct(u8) {
|
||||||
GPIO0: bool,
|
GPIO0: bool,
|
||||||
GPIO1: bool,
|
GPIO1: bool,
|
||||||
GPIO2: bool,
|
GPIO2: bool,
|
||||||
GPIO3: bool,
|
GPIO3: bool,
|
||||||
_reserved: u4 = 0,
|
reserved: u4 = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Write a new state to the memory-mapped IO.
|
const gpio: *volatile GpioRegister = @ptrFromInt(0x0123);
|
||||||
pub fn writeToGPIO(new_states: GPIORegister) void {
|
|
||||||
const gpio_register_address = 0x0123;
|
pub fn writeToGpio(new_states: GpioRegister) void {
|
||||||
const raw_ptr: *align(1) volatile GPIORegister = @ptrFromInt(gpio_register_address);
|
// Example of what not to do:
|
||||||
raw_ptr.* = new_states;
|
// BAD! gpio.GPIO0 = true; BAD!
|
||||||
|
|
||||||
|
// Instead, do this:
|
||||||
|
gpio.* = new_states;
|
||||||
}
|
}
|
||||||
|
|
||||||
// syntax
|
// syntax
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user