authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-22 10:56:49-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-22 10:56:49-05:00
logd0c39895aae085e421ada85d9d07f417d549c7e6
treee21f4cb764cbda0cc6fcc2aaa5e69c83a391794a
parent0c5f8979045ff05e713bb1b7341496012189650f
signaturelock-open Commit is signed but in an unrecognized format.

docs for packed structs

closes #1513

1 files changed, 228 insertions(+), 32 deletions(-)

doc/langref.html.in+228-32
......@@ -8,13 +8,7 @@
88 body{
99 background-color:#111;
1010 color: #bbb;
11 font-family: system-ui,
12 /* Fallbacks for browsers that don't support system-ui */
13 /* https://caniuse.com/#search=system-ui */
14 -apple-system, /* iOS and macOS */
15 Roboto, /* Android */
16 "Segoe UI", /* Windows */
17 sans-serif;
11 font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
1812 }
1913 a {
2014 color: #88f;
......@@ -263,7 +257,7 @@ pub fn main() void {
263257 true and false,
264258 true or false,
265259 !true);
266
260
267261 // optional
268262 var optional_value: ?[]const u8 = null;
269263 assert(optional_value == null);
......@@ -282,7 +276,7 @@ pub fn main() void {
282276
283277 warn("\nerror union 1\ntype: {}\nvalue: {}\n",
284278 @typeName(@typeOf(number_or_error)), number_or_error);
285
279
286280 number_or_error = 1234;
287281
288282 warn("\nerror union 2\ntype: {}\nvalue: {}\n",
......@@ -707,15 +701,21 @@ fn divide(a: i32, b: i32) i32 {
707701 {#code_end#}
708702 <p>
709703 In this function, values {#syntax#}a{#endsyntax#} and {#syntax#}b{#endsyntax#} are known only at runtime,
710 and thus this division operation is vulnerable to both integer overflow and
711 division by zero.
704 and thus this division operation is vulnerable to both {#link|Integer Overflow#} and
705 {#link|Division by Zero#}.
712706 </p>
713707 <p>
714708 Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause undefined behavior on
715709 integer overflow. Also available are operations such as {#syntax#}+%{#endsyntax#} and
716710 {#syntax#}-%{#endsyntax#} which are defined to have wrapping arithmetic on all targets.
717711 </p>
718 {#see_also|Integer Overflow|Division by Zero|Wrapping Operations#}
712 <p>
713 Zig supports arbitrary bit-width integers, referenced by using
714 an identifier of <code>i</code> or </code>u</code> followed by digits. For example, the identifier
715 {#syntax#}i7{#endsyntax#} refers to a signed 7-bit integer. The maximum allowed bit-width of an
716 integer type is {#syntax#}65535{#endsyntax#}.
717 </p>
718 {#see_also|Wrapping Operations#}
719719 {#header_close#}
720720 {#header_close#}
721721 {#header_open|Floats#}
......@@ -1652,7 +1652,7 @@ test "pointer slicing" {
16521652 assert(array[3] == 5);
16531653}
16541654 {#code_end#}
1655 <p>Pointers work at compile-time too, as long as the code does not depend on
1655 <p>Pointers work at compile-time too, as long as the code does not depend on
16561656 an undefined memory layout:</p>
16571657 {#code_begin|test#}
16581658const assert = @import("std").debug.assert;
......@@ -2047,13 +2047,203 @@ test "linked list" {
20472047}
20482048 {#code_end#}
20492049 {#header_open|packed struct#}
2050 <p>{#syntax#}packed{#endsyntax#} structs have guaranteed in-memory layout.</p>
2051 <p>TODO bit fields</p>
2052 <p>TODO alignment</p>
2053 <p>TODO endianness</p>
2054 <p>TODO @bitOffsetOf and @byteOffsetOf</p>
2055 <p>TODO mention how volatile loads and stores of bit packed fields could be more efficient when
2056 done by hand instead of with packed struct</p>
2050 <p>
2051 Unlike normal structs, {#syntax#}packed{#endsyntax#} structs have guaranteed in-memory layout:
2052 </p>
2053 <ul>
2054 <li>Fields remain in the order declared.</li>
2055 <li>There is no padding between fields.</li>
2056 <li>Zig supports arbitrary width {#link|Integers#} and although normally, integers with fewer
2057 than 8 bits will still use 1 byte of memory, in packed structs, they use
2058 exactly their bit width.
2059 </li>
2060 <li>{#syntax#}bool{#endsyntax#} fields use exactly 1 bit.</li>
2061 <li>A {#link|packed enum#} field uses exactly the bit width of its integer tag type.</li>
2062 <li>A {#link|packed union#} field uses exactly the bit width of the union field with
2063 the largest bit width.</li>
2064 <li>Non-byte-aligned fields are packed into the smallest possible
2065 byte-aligned integers in accordance with the target endianness.
2066 </li>
2067 </ul>
2068 <p>
2069 This means that a {#syntax#}packed struct{#endsyntax#} can participate
2070 in a {#link|@bitCast#} or a {#link|@ptrCast#} to reinterpret memory.
2071 This even works at {#link|comptime#}:
2072 </p>
2073 {#code_begin|test#}
2074const std = @import("std");
2075const builtin = @import("builtin");
2076const assert = std.debug.assert;
2077
2078const Full = packed struct {
2079 number: u16,
2080};
2081const Divided = packed struct {
2082 half1: u8,
2083 quarter3: u4,
2084 quarter4: u4,
2085};
2086
2087test "@bitCast between packed structs" {
2088 doTheTest();
2089 comptime doTheTest();
2090}
2091
2092fn doTheTest() void {
2093 assert(@sizeOf(Full) == 2);
2094 assert(@sizeOf(Divided) == 2);
2095 var full = Full{ .number = 0x1234 };
2096 var divided = @bitCast(Divided, full);
2097 switch (builtin.endian) {
2098 builtin.Endian.Big => {
2099 assert(divided.half1 == 0x12);
2100 assert(divided.quarter3 == 0x3);
2101 assert(divided.quarter4 == 0x4);
2102 },
2103 builtin.Endian.Little => {
2104 assert(divided.half1 == 0x34);
2105 assert(divided.quarter3 == 0x2);
2106 assert(divided.quarter4 == 0x1);
2107 },
2108 }
2109}
2110 {#code_end#}
2111 <p>
2112 Zig allows the address to be taken of a non-byte-aligned field:
2113 </p>
2114 {#code_begin|test#}
2115const std = @import("std");
2116const assert = std.debug.assert;
2117
2118const BitField = packed struct {
2119 a: u3,
2120 b: u3,
2121 c: u2,
2122};
2123
2124var foo = BitField{
2125 .a = 1,
2126 .b = 2,
2127 .c = 3,
2128};
2129
2130test "pointer to non-byte-aligned field" {
2131 const ptr = &foo.b;
2132 assert(ptr.* == 2);
2133}
2134 {#code_end#}
2135 <p>
2136 However, the pointer to a non-byte-aligned field has special properties and cannot
2137 be passed when a normal pointer is expected:
2138 </p>
2139 {#code_begin|test_err|expected type#}
2140const std = @import("std");
2141const assert = std.debug.assert;
2142
2143const BitField = packed struct {
2144 a: u3,
2145 b: u3,
2146 c: u2,
2147};
2148
2149var bit_field = BitField{
2150 .a = 1,
2151 .b = 2,
2152 .c = 3,
2153};
2154
2155test "pointer to non-bit-aligned field" {
2156 assert(bar(&bit_field.b) == 2);
2157}
2158
2159fn bar(x: *const u3) u3 {
2160 return x.*;
2161}
2162 {#code_end#}
2163 <p>
2164 In this case, the function {#syntax#}bar{#endsyntax#} cannot be called becuse the pointer
2165 to the non-byte-aligned field mentions the bit offset, but the function expects a byte-aligned pointer.
2166 </p>
2167 <p>
2168 Pointers to non-byte-aligned fields share the same address as the other fields within their host integer:
2169 </p>
2170 {#code_begin|test#}
2171const std = @import("std");
2172const assert = std.debug.assert;
2173
2174const BitField = packed struct {
2175 a: u3,
2176 b: u3,
2177 c: u2,
2178};
2179
2180var bit_field = BitField{
2181 .a = 1,
2182 .b = 2,
2183 .c = 3,
2184};
2185
2186test "pointer to non-bit-aligned field" {
2187 assert(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.b));
2188 assert(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.c));
2189}
2190 {#code_end#}
2191 <p>
2192 This can be observed with {#link|@bitOffsetOf#} and {#link|byteOffsetOf#}:
2193 </p>
2194 {#code_begin|test#}
2195const std = @import("std");
2196const assert = std.debug.assert;
2197
2198const BitField = packed struct {
2199 a: u3,
2200 b: u3,
2201 c: u2,
2202};
2203
2204test "pointer to non-bit-aligned field" {
2205 comptime {
2206 assert(@bitOffsetOf(BitField, "a") == 0);
2207 assert(@bitOffsetOf(BitField, "b") == 3);
2208 assert(@bitOffsetOf(BitField, "c") == 6);
2209
2210 assert(@byteOffsetOf(BitField, "a") == 0);
2211 assert(@byteOffsetOf(BitField, "b") == 0);
2212 assert(@byteOffsetOf(BitField, "c") == 0);
2213 }
2214}
2215 {#code_end#}
2216 <p>
2217 Packed structs have 1-byte alignment. However if you have an overaligned pointer to a packed struct,
2218 Zig should correctly understand the alignment of fields. However there is
2219 <a href="https://github.com/ziglang/zig/issues/1994">a bug</a>:
2220 </p>
2221 {#code_begin|test_err#}
2222const S = packed struct {
2223 a: u32,
2224 b: u32,
2225};
2226test "overaligned pointer to packed struct" {
2227 var foo: S align(4) = undefined;
2228 const ptr: *align(4) S = &foo;
2229 const ptr_to_b: *u32 = &ptr.b;
2230}
2231 {#code_end#}
2232 <p>When this bug is fixed, the above test in the documentation will unexpectedly pass, which will
2233 cause the test suite to fail, notifying the bug fixer to update these docs.
2234 </p>
2235 <p>
2236 It's also
2237 <a href="https://github.com/ziglang/zig/issues/1512">planned to be able to set alignment of struct fields</a>.
2238 </p>
2239 <p>
2240 Using packed structs with {#link|volatile#} is problematic, and may be a compile error in the future.
2241 For details on this subscribe to
2242 <a href="https://github.com/ziglang/zig/issues/1761">this issue</a>.
2243 TODO update these docs with a recommendation on how to use packed structs with MMIO
2244 (the use case for volatile packed structs) once this issue is resolved.
2245 Don't worry, there will be a good solution for this use case in zig.
2246 </p>
20572247 {#header_close#}
20582248 {#header_open|struct Naming#}
20592249 <p>Since all structs are anonymous, Zig infers the type name based on a few rules.</p>
......@@ -2203,8 +2393,8 @@ export fn entry(foo: Foo) void { }
22032393 {#header_close#}
22042394 {#header_open|packed enum#}
22052395 <p>By default, the size of enums is not guaranteed.</p>
2206 <p>{#syntax#}packed enum{#endsyntax#} causes the size of the enum to be the same as the size of the integer tag type
2207 of the enum:</p>
2396 <p>{#syntax#}packed enum{#endsyntax#} causes the size of the enum to be the same as the size of the
2397 integer tag type of the enum:</p>
22082398 {#code_begin|test#}
22092399const std = @import("std");
22102400
......@@ -2217,6 +2407,7 @@ test "packed enum" {
22172407 std.debug.assert(@sizeOf(Number) == @sizeOf(u8));
22182408}
22192409 {#code_end#}
2410 <p>This makes the enum eligible to be in a {#link|packed struct#}.</p>
22202411 {#header_close#}
22212412 {#see_also|@memberName|@memberCount|@tagName|@sizeOf#}
22222413 {#header_close#}
......@@ -2344,7 +2535,12 @@ test "@tagName" {
23442535 Unions with an enum tag are generated as a struct with a tag field and union field. Zig
23452536 sorts the order of the tag and union field by the largest alignment.
23462537 </p>
2538 {#header_open|packed union#}
2539 <p>A {#syntax#}packed union{#endsyntax#} has well-defined in-memory layout and is eligible
2540 to be in a {#link|packed struct#}.
2541 {#header_close#}
23472542 {#header_close#}
2543
23482544 {#header_open|blocks#}
23492545 <p>
23502546 Blocks are used to limit the scope of variable declarations:
......@@ -3771,7 +3967,7 @@ fn bang2() void {
37713967 Here, the stack trace does not explain how the control
37723968 flow in {#syntax#}bar{#endsyntax#} got to the {#syntax#}hello(){#endsyntax#} call.
37733969 One would have to open a debugger or further instrument the application
3774 in order to find out. The error return trace, on the other hand,
3970 in order to find out. The error return trace, on the other hand,
37753971 shows exactly how the error bubbled up.
37763972 </p>
37773973 <p>
......@@ -3963,7 +4159,7 @@ test "optional type" {
39634159 cast it to a different type:
39644160 </p>
39654161 {#code_begin|syntax#}
3966const optional_value: ?i32 = null;
4162const optional_value: ?i32 = null;
39674163 {#code_end#}
39684164 {#header_close#}
39694165 {#header_open|Optional Pointers#}
......@@ -5141,7 +5337,7 @@ async fn testResumeFromSuspend(my_result: *i32) void {
51415337 <p>
51425338 {#syntax#}await{#endsyntax#} is valid only in an {#syntax#}async{#endsyntax#} function, and it takes
51435339 as an operand a promise handle.
5144 If the async function associated with the promise handle has already returned,
5340 If the async function associated with the promise handle has already returned,
51455341 then {#syntax#}await{#endsyntax#} destroys the target async function, and gives the return value.
51465342 Otherwise, {#syntax#}await{#endsyntax#} suspends the current async function, registering its
51475343 promise handle with the target coroutine. It becomes the target coroutine's responsibility
......@@ -5225,7 +5421,7 @@ fn seq(c: u8) void {
52255421 </li>
52265422 </ul>
52275423 {#header_close#}
5228
5424
52295425 {#header_close#}
52305426 {#header_open|Builtin Functions#}
52315427 <p>
......@@ -5580,13 +5776,13 @@ const warn = @import("std").debug.warn;
55805776
55815777const num1 = blk: {
55825778 var val1: i32 = 99;
5583 @compileLog("comptime val1 = ", val1);
5779 @compileLog("comptime val1 = ", val1);
55845780 val1 = val1 + 1;
55855781 break :blk val1;
55865782};
55875783
55885784test "main" {
5589 @compileLog("comptime in main");
5785 @compileLog("comptime in main");
55905786
55915787 warn("Runtime in main, num1 = {}.\n", num1);
55925788}
......@@ -5596,10 +5792,10 @@ test "main" {
55965792 will ouput:
55975793 </p>
55985794 <p>
5599 If all {#syntax#}@compileLog{#endsyntax#} calls are removed or
5795 If all {#syntax#}@compileLog{#endsyntax#} calls are removed or
56005796 not encountered by analysis, the
56015797 program compiles successfully and the generated executable prints:
5602 </p>
5798 </p>
56035799 {#code_begin|test#}
56045800const warn = @import("std").debug.warn;
56055801
......@@ -6425,7 +6621,7 @@ fn List(comptime T: type) type {
64256621 <p>
64266622 When {#syntax#}@This(){#endsyntax#} is used at global scope, it returns a reference to the
64276623 current import. There is a proposal to remove the import type and use an empty struct
6428 type instead. See
6624 type instead. See
64296625 <a href="https://github.com/ziglang/zig/issues/1047">#1047</a> for details.
64306626 </p>
64316627 {#header_close#}
......@@ -7560,7 +7756,7 @@ const c = @cImport({
75607756 {#link|Undefined Behavior#} occurs if the address is 0.
75617757 </li>
75627758 <li>Allows address 0. On non-freestanding targets, dereferencing address 0 is safety-checked
7563 {#link|Undefined Behavior#}. Optional C pointers introduce another bit to keep track of
7759 {#link|Undefined Behavior#}. Optional C pointers introduce another bit to keep track of
75647760 null, just like {#syntax#}?usize{#endsyntax#}. Note that creating an optional C pointer
75657761 is unnecessary as one can use normal {#link|Optional Pointers#}.
75667762 </li>