| ... | ... | @@ -8,13 +8,7 @@ |
| 8 | 8 | body{ |
| 9 | 9 | background-color:#111; |
| 10 | 10 | 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; |
| 18 | 12 | } |
| 19 | 13 | a { |
| 20 | 14 | color: #88f; |
| ... | ... | @@ -263,7 +257,7 @@ pub fn main() void { |
| 263 | 257 | true and false, |
| 264 | 258 | true or false, |
| 265 | 259 | !true); |
| 266 | | |
| 260 | |
| 267 | 261 | // optional |
| 268 | 262 | var optional_value: ?[]const u8 = null; |
| 269 | 263 | assert(optional_value == null); |
| ... | ... | @@ -282,7 +276,7 @@ pub fn main() void { |
| 282 | 276 | |
| 283 | 277 | warn("\nerror union 1\ntype: {}\nvalue: {}\n", |
| 284 | 278 | @typeName(@typeOf(number_or_error)), number_or_error); |
| 285 | | |
| 279 | |
| 286 | 280 | number_or_error = 1234; |
| 287 | 281 | |
| 288 | 282 | warn("\nerror union 2\ntype: {}\nvalue: {}\n", |
| ... | ... | @@ -707,15 +701,21 @@ fn divide(a: i32, b: i32) i32 { |
| 707 | 701 | {#code_end#} |
| 708 | 702 | <p> |
| 709 | 703 | 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#}. |
| 712 | 706 | </p> |
| 713 | 707 | <p> |
| 714 | 708 | Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause undefined behavior on |
| 715 | 709 | integer overflow. Also available are operations such as {#syntax#}+%{#endsyntax#} and |
| 716 | 710 | {#syntax#}-%{#endsyntax#} which are defined to have wrapping arithmetic on all targets. |
| 717 | 711 | </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#} |
| 719 | 719 | {#header_close#} |
| 720 | 720 | {#header_close#} |
| 721 | 721 | {#header_open|Floats#} |
| ... | ... | @@ -1652,7 +1652,7 @@ test "pointer slicing" { |
| 1652 | 1652 | assert(array[3] == 5); |
| 1653 | 1653 | } |
| 1654 | 1654 | {#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 |
| 1656 | 1656 | an undefined memory layout:</p> |
| 1657 | 1657 | {#code_begin|test#} |
| 1658 | 1658 | const assert = @import("std").debug.assert; |
| ... | ... | @@ -2047,13 +2047,203 @@ test "linked list" { |
| 2047 | 2047 | } |
| 2048 | 2048 | {#code_end#} |
| 2049 | 2049 | {#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#} |
| 2074 | const std = @import("std"); |
| 2075 | const builtin = @import("builtin"); |
| 2076 | const assert = std.debug.assert; |
| 2077 | |
| 2078 | const Full = packed struct { |
| 2079 | number: u16, |
| 2080 | }; |
| 2081 | const Divided = packed struct { |
| 2082 | half1: u8, |
| 2083 | quarter3: u4, |
| 2084 | quarter4: u4, |
| 2085 | }; |
| 2086 | |
| 2087 | test "@bitCast between packed structs" { |
| 2088 | doTheTest(); |
| 2089 | comptime doTheTest(); |
| 2090 | } |
| 2091 | |
| 2092 | fn 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#} |
| 2115 | const std = @import("std"); |
| 2116 | const assert = std.debug.assert; |
| 2117 | |
| 2118 | const BitField = packed struct { |
| 2119 | a: u3, |
| 2120 | b: u3, |
| 2121 | c: u2, |
| 2122 | }; |
| 2123 | |
| 2124 | var foo = BitField{ |
| 2125 | .a = 1, |
| 2126 | .b = 2, |
| 2127 | .c = 3, |
| 2128 | }; |
| 2129 | |
| 2130 | test "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#} |
| 2140 | const std = @import("std"); |
| 2141 | const assert = std.debug.assert; |
| 2142 | |
| 2143 | const BitField = packed struct { |
| 2144 | a: u3, |
| 2145 | b: u3, |
| 2146 | c: u2, |
| 2147 | }; |
| 2148 | |
| 2149 | var bit_field = BitField{ |
| 2150 | .a = 1, |
| 2151 | .b = 2, |
| 2152 | .c = 3, |
| 2153 | }; |
| 2154 | |
| 2155 | test "pointer to non-bit-aligned field" { |
| 2156 | assert(bar(&bit_field.b) == 2); |
| 2157 | } |
| 2158 | |
| 2159 | fn 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#} |
| 2171 | const std = @import("std"); |
| 2172 | const assert = std.debug.assert; |
| 2173 | |
| 2174 | const BitField = packed struct { |
| 2175 | a: u3, |
| 2176 | b: u3, |
| 2177 | c: u2, |
| 2178 | }; |
| 2179 | |
| 2180 | var bit_field = BitField{ |
| 2181 | .a = 1, |
| 2182 | .b = 2, |
| 2183 | .c = 3, |
| 2184 | }; |
| 2185 | |
| 2186 | test "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#} |
| 2195 | const std = @import("std"); |
| 2196 | const assert = std.debug.assert; |
| 2197 | |
| 2198 | const BitField = packed struct { |
| 2199 | a: u3, |
| 2200 | b: u3, |
| 2201 | c: u2, |
| 2202 | }; |
| 2203 | |
| 2204 | test "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#} |
| 2222 | const S = packed struct { |
| 2223 | a: u32, |
| 2224 | b: u32, |
| 2225 | }; |
| 2226 | test "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> |
| 2057 | 2247 | {#header_close#} |
| 2058 | 2248 | {#header_open|struct Naming#} |
| 2059 | 2249 | <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 { } |
| 2203 | 2393 | {#header_close#} |
| 2204 | 2394 | {#header_open|packed enum#} |
| 2205 | 2395 | <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> |
| 2208 | 2398 | {#code_begin|test#} |
| 2209 | 2399 | const std = @import("std"); |
| 2210 | 2400 | |
| ... | ... | @@ -2217,6 +2407,7 @@ test "packed enum" { |
| 2217 | 2407 | std.debug.assert(@sizeOf(Number) == @sizeOf(u8)); |
| 2218 | 2408 | } |
| 2219 | 2409 | {#code_end#} |
| 2410 | <p>This makes the enum eligible to be in a {#link|packed struct#}.</p> |
| 2220 | 2411 | {#header_close#} |
| 2221 | 2412 | {#see_also|@memberName|@memberCount|@tagName|@sizeOf#} |
| 2222 | 2413 | {#header_close#} |
| ... | ... | @@ -2344,7 +2535,12 @@ test "@tagName" { |
| 2344 | 2535 | Unions with an enum tag are generated as a struct with a tag field and union field. Zig |
| 2345 | 2536 | sorts the order of the tag and union field by the largest alignment. |
| 2346 | 2537 | </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#} |
| 2347 | 2542 | {#header_close#} |
| 2543 | |
| 2348 | 2544 | {#header_open|blocks#} |
| 2349 | 2545 | <p> |
| 2350 | 2546 | Blocks are used to limit the scope of variable declarations: |
| ... | ... | @@ -3771,7 +3967,7 @@ fn bang2() void { |
| 3771 | 3967 | Here, the stack trace does not explain how the control |
| 3772 | 3968 | flow in {#syntax#}bar{#endsyntax#} got to the {#syntax#}hello(){#endsyntax#} call. |
| 3773 | 3969 | 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, |
| 3775 | 3971 | shows exactly how the error bubbled up. |
| 3776 | 3972 | </p> |
| 3777 | 3973 | <p> |
| ... | ... | @@ -3963,7 +4159,7 @@ test "optional type" { |
| 3963 | 4159 | cast it to a different type: |
| 3964 | 4160 | </p> |
| 3965 | 4161 | {#code_begin|syntax#} |
| 3966 | | const optional_value: ?i32 = null; |
| 4162 | const optional_value: ?i32 = null; |
| 3967 | 4163 | {#code_end#} |
| 3968 | 4164 | {#header_close#} |
| 3969 | 4165 | {#header_open|Optional Pointers#} |
| ... | ... | @@ -5141,7 +5337,7 @@ async fn testResumeFromSuspend(my_result: *i32) void { |
| 5141 | 5337 | <p> |
| 5142 | 5338 | {#syntax#}await{#endsyntax#} is valid only in an {#syntax#}async{#endsyntax#} function, and it takes |
| 5143 | 5339 | 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, |
| 5145 | 5341 | then {#syntax#}await{#endsyntax#} destroys the target async function, and gives the return value. |
| 5146 | 5342 | Otherwise, {#syntax#}await{#endsyntax#} suspends the current async function, registering its |
| 5147 | 5343 | promise handle with the target coroutine. It becomes the target coroutine's responsibility |
| ... | ... | @@ -5225,7 +5421,7 @@ fn seq(c: u8) void { |
| 5225 | 5421 | </li> |
| 5226 | 5422 | </ul> |
| 5227 | 5423 | {#header_close#} |
| 5228 | | |
| 5424 | |
| 5229 | 5425 | {#header_close#} |
| 5230 | 5426 | {#header_open|Builtin Functions#} |
| 5231 | 5427 | <p> |
| ... | ... | @@ -5580,13 +5776,13 @@ const warn = @import("std").debug.warn; |
| 5580 | 5776 | |
| 5581 | 5777 | const num1 = blk: { |
| 5582 | 5778 | var val1: i32 = 99; |
| 5583 | | @compileLog("comptime val1 = ", val1); |
| 5779 | @compileLog("comptime val1 = ", val1); |
| 5584 | 5780 | val1 = val1 + 1; |
| 5585 | 5781 | break :blk val1; |
| 5586 | 5782 | }; |
| 5587 | 5783 | |
| 5588 | 5784 | test "main" { |
| 5589 | | @compileLog("comptime in main"); |
| 5785 | @compileLog("comptime in main"); |
| 5590 | 5786 | |
| 5591 | 5787 | warn("Runtime in main, num1 = {}.\n", num1); |
| 5592 | 5788 | } |
| ... | ... | @@ -5596,10 +5792,10 @@ test "main" { |
| 5596 | 5792 | will ouput: |
| 5597 | 5793 | </p> |
| 5598 | 5794 | <p> |
| 5599 | | If all {#syntax#}@compileLog{#endsyntax#} calls are removed or |
| 5795 | If all {#syntax#}@compileLog{#endsyntax#} calls are removed or |
| 5600 | 5796 | not encountered by analysis, the |
| 5601 | 5797 | program compiles successfully and the generated executable prints: |
| 5602 | | </p> |
| 5798 | </p> |
| 5603 | 5799 | {#code_begin|test#} |
| 5604 | 5800 | const warn = @import("std").debug.warn; |
| 5605 | 5801 | |
| ... | ... | @@ -6425,7 +6621,7 @@ fn List(comptime T: type) type { |
| 6425 | 6621 | <p> |
| 6426 | 6622 | When {#syntax#}@This(){#endsyntax#} is used at global scope, it returns a reference to the |
| 6427 | 6623 | current import. There is a proposal to remove the import type and use an empty struct |
| 6428 | | type instead. See |
| 6624 | type instead. See |
| 6429 | 6625 | <a href="https://github.com/ziglang/zig/issues/1047">#1047</a> for details. |
| 6430 | 6626 | </p> |
| 6431 | 6627 | {#header_close#} |
| ... | ... | @@ -7560,7 +7756,7 @@ const c = @cImport({ |
| 7560 | 7756 | {#link|Undefined Behavior#} occurs if the address is 0. |
| 7561 | 7757 | </li> |
| 7562 | 7758 | <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 |
| 7564 | 7760 | null, just like {#syntax#}?usize{#endsyntax#}. Note that creating an optional C pointer |
| 7565 | 7761 | is unnecessary as one can use normal {#link|Optional Pointers#}. |
| 7566 | 7762 | </li> |