| ... | @@ -8,13 +8,7 @@ | ... | @@ -8,13 +8,7 @@ |
| 8 | body{ | 8 | body{ |
| 9 | background-color:#111; | 9 | background-color:#111; |
| 10 | color: #bbb; | 10 | color: #bbb; |
| 11 | font-family: system-ui, | 11 | font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif; |
| 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; | | |
| 18 | } | 12 | } |
| 19 | a { | 13 | a { |
| 20 | color: #88f; | 14 | color: #88f; |
| ... | @@ -263,7 +257,7 @@ pub fn main() void { | ... | @@ -263,7 +257,7 @@ pub fn main() void { |
| 263 | true and false, | 257 | true and false, |
| 264 | true or false, | 258 | true or false, |
| 265 | !true); | 259 | !true); |
| 266 | | 260 | |
| 267 | // optional | 261 | // optional |
| 268 | var optional_value: ?[]const u8 = null; | 262 | var optional_value: ?[]const u8 = null; |
| 269 | assert(optional_value == null); | 263 | assert(optional_value == null); |
| ... | @@ -282,7 +276,7 @@ pub fn main() void { | ... | @@ -282,7 +276,7 @@ pub fn main() void { |
| 282 | | 276 | |
| 283 | warn("\nerror union 1\ntype: {}\nvalue: {}\n", | 277 | warn("\nerror union 1\ntype: {}\nvalue: {}\n", |
| 284 | @typeName(@typeOf(number_or_error)), number_or_error); | 278 | @typeName(@typeOf(number_or_error)), number_or_error); |
| 285 | | 279 | |
| 286 | number_or_error = 1234; | 280 | number_or_error = 1234; |
| 287 | | 281 | |
| 288 | warn("\nerror union 2\ntype: {}\nvalue: {}\n", | 282 | warn("\nerror union 2\ntype: {}\nvalue: {}\n", |
| ... | @@ -707,15 +701,21 @@ fn divide(a: i32, b: i32) i32 { | ... | @@ -707,15 +701,21 @@ fn divide(a: i32, b: i32) i32 { |
| 707 | {#code_end#} | 701 | {#code_end#} |
| 708 | <p> | 702 | <p> |
| 709 | In this function, values {#syntax#}a{#endsyntax#} and {#syntax#}b{#endsyntax#} are known only at runtime, | 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 | 704 | and thus this division operation is vulnerable to both {#link|Integer Overflow#} and |
| 711 | division by zero. | 705 | {#link|Division by Zero#}. |
| 712 | </p> | 706 | </p> |
| 713 | <p> | 707 | <p> |
| 714 | Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause undefined behavior on | 708 | Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause undefined behavior on |
| 715 | integer overflow. Also available are operations such as {#syntax#}+%{#endsyntax#} and | 709 | integer overflow. Also available are operations such as {#syntax#}+%{#endsyntax#} and |
| 716 | {#syntax#}-%{#endsyntax#} which are defined to have wrapping arithmetic on all targets. | 710 | {#syntax#}-%{#endsyntax#} which are defined to have wrapping arithmetic on all targets. |
| 717 | </p> | 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 | {#header_close#} | 719 | {#header_close#} |
| 720 | {#header_close#} | 720 | {#header_close#} |
| 721 | {#header_open|Floats#} | 721 | {#header_open|Floats#} |
| ... | @@ -1652,7 +1652,7 @@ test "pointer slicing" { | ... | @@ -1652,7 +1652,7 @@ test "pointer slicing" { |
| 1652 | assert(array[3] == 5); | 1652 | assert(array[3] == 5); |
| 1653 | } | 1653 | } |
| 1654 | {#code_end#} | 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 | an undefined memory layout:</p> | 1656 | an undefined memory layout:</p> |
| 1657 | {#code_begin|test#} | 1657 | {#code_begin|test#} |
| 1658 | const assert = @import("std").debug.assert; | 1658 | const assert = @import("std").debug.assert; |
| ... | @@ -2047,13 +2047,203 @@ test "linked list" { | ... | @@ -2047,13 +2047,203 @@ test "linked list" { |
| 2047 | } | 2047 | } |
| 2048 | {#code_end#} | 2048 | {#code_end#} |
| 2049 | {#header_open|packed struct#} | 2049 | {#header_open|packed struct#} |
| 2050 | <p>{#syntax#}packed{#endsyntax#} structs have guaranteed in-memory layout.</p> | 2050 | <p> |
| 2051 | <p>TODO bit fields</p> | 2051 | Unlike normal structs, {#syntax#}packed{#endsyntax#} structs have guaranteed in-memory layout: |
| 2052 | <p>TODO alignment</p> | 2052 | </p> |
| 2053 | <p>TODO endianness</p> | 2053 | <ul> |
| 2054 | <p>TODO @bitOffsetOf and @byteOffsetOf</p> | 2054 | <li>Fields remain in the order declared.</li> |
| 2055 | <p>TODO mention how volatile loads and stores of bit packed fields could be more efficient when | 2055 | <li>There is no padding between fields.</li> |
| 2056 | done by hand instead of with packed struct</p> | 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 | {#header_close#} | 2247 | {#header_close#} |
| 2058 | {#header_open|struct Naming#} | 2248 | {#header_open|struct Naming#} |
| 2059 | <p>Since all structs are anonymous, Zig infers the type name based on a few rules.</p> | 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,8 +2393,8 @@ export fn entry(foo: Foo) void { } |
| 2203 | {#header_close#} | 2393 | {#header_close#} |
| 2204 | {#header_open|packed enum#} | 2394 | {#header_open|packed enum#} |
| 2205 | <p>By default, the size of enums is not guaranteed.</p> | 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 | 2396 | <p>{#syntax#}packed enum{#endsyntax#} causes the size of the enum to be the same as the size of the |
| 2207 | of the enum:</p> | 2397 | integer tag type of the enum:</p> |
| 2208 | {#code_begin|test#} | 2398 | {#code_begin|test#} |
| 2209 | const std = @import("std"); | 2399 | const std = @import("std"); |
| 2210 | | 2400 | |
| ... | @@ -2217,6 +2407,7 @@ test "packed enum" { | ... | @@ -2217,6 +2407,7 @@ test "packed enum" { |
| 2217 | std.debug.assert(@sizeOf(Number) == @sizeOf(u8)); | 2407 | std.debug.assert(@sizeOf(Number) == @sizeOf(u8)); |
| 2218 | } | 2408 | } |
| 2219 | {#code_end#} | 2409 | {#code_end#} |
| | 2410 | <p>This makes the enum eligible to be in a {#link|packed struct#}.</p> |
| 2220 | {#header_close#} | 2411 | {#header_close#} |
| 2221 | {#see_also|@memberName|@memberCount|@tagName|@sizeOf#} | 2412 | {#see_also|@memberName|@memberCount|@tagName|@sizeOf#} |
| 2222 | {#header_close#} | 2413 | {#header_close#} |
| ... | @@ -2344,7 +2535,12 @@ test "@tagName" { | ... | @@ -2344,7 +2535,12 @@ test "@tagName" { |
| 2344 | Unions with an enum tag are generated as a struct with a tag field and union field. Zig | 2535 | Unions with an enum tag are generated as a struct with a tag field and union field. Zig |
| 2345 | sorts the order of the tag and union field by the largest alignment. | 2536 | sorts the order of the tag and union field by the largest alignment. |
| 2346 | </p> | 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 | {#header_close#} | 2542 | {#header_close#} |
| | 2543 | |
| 2348 | {#header_open|blocks#} | 2544 | {#header_open|blocks#} |
| 2349 | <p> | 2545 | <p> |
| 2350 | Blocks are used to limit the scope of variable declarations: | 2546 | Blocks are used to limit the scope of variable declarations: |
| ... | @@ -3771,7 +3967,7 @@ fn bang2() void { | ... | @@ -3771,7 +3967,7 @@ fn bang2() void { |
| 3771 | Here, the stack trace does not explain how the control | 3967 | Here, the stack trace does not explain how the control |
| 3772 | flow in {#syntax#}bar{#endsyntax#} got to the {#syntax#}hello(){#endsyntax#} call. | 3968 | flow in {#syntax#}bar{#endsyntax#} got to the {#syntax#}hello(){#endsyntax#} call. |
| 3773 | One would have to open a debugger or further instrument the application | 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 | shows exactly how the error bubbled up. | 3971 | shows exactly how the error bubbled up. |
| 3776 | </p> | 3972 | </p> |
| 3777 | <p> | 3973 | <p> |
| ... | @@ -3963,7 +4159,7 @@ test "optional type" { | ... | @@ -3963,7 +4159,7 @@ test "optional type" { |
| 3963 | cast it to a different type: | 4159 | cast it to a different type: |
| 3964 | </p> | 4160 | </p> |
| 3965 | {#code_begin|syntax#} | 4161 | {#code_begin|syntax#} |
| 3966 | const optional_value: ?i32 = null; | 4162 | const optional_value: ?i32 = null; |
| 3967 | {#code_end#} | 4163 | {#code_end#} |
| 3968 | {#header_close#} | 4164 | {#header_close#} |
| 3969 | {#header_open|Optional Pointers#} | 4165 | {#header_open|Optional Pointers#} |
| ... | @@ -5141,7 +5337,7 @@ async fn testResumeFromSuspend(my_result: *i32) void { | ... | @@ -5141,7 +5337,7 @@ async fn testResumeFromSuspend(my_result: *i32) void { |
| 5141 | <p> | 5337 | <p> |
| 5142 | {#syntax#}await{#endsyntax#} is valid only in an {#syntax#}async{#endsyntax#} function, and it takes | 5338 | {#syntax#}await{#endsyntax#} is valid only in an {#syntax#}async{#endsyntax#} function, and it takes |
| 5143 | as an operand a promise handle. | 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 | then {#syntax#}await{#endsyntax#} destroys the target async function, and gives the return value. | 5341 | then {#syntax#}await{#endsyntax#} destroys the target async function, and gives the return value. |
| 5146 | Otherwise, {#syntax#}await{#endsyntax#} suspends the current async function, registering its | 5342 | Otherwise, {#syntax#}await{#endsyntax#} suspends the current async function, registering its |
| 5147 | promise handle with the target coroutine. It becomes the target coroutine's responsibility | 5343 | promise handle with the target coroutine. It becomes the target coroutine's responsibility |
| ... | @@ -5225,7 +5421,7 @@ fn seq(c: u8) void { | ... | @@ -5225,7 +5421,7 @@ fn seq(c: u8) void { |
| 5225 | </li> | 5421 | </li> |
| 5226 | </ul> | 5422 | </ul> |
| 5227 | {#header_close#} | 5423 | {#header_close#} |
| 5228 | | 5424 | |
| 5229 | {#header_close#} | 5425 | {#header_close#} |
| 5230 | {#header_open|Builtin Functions#} | 5426 | {#header_open|Builtin Functions#} |
| 5231 | <p> | 5427 | <p> |
| ... | @@ -5580,13 +5776,13 @@ const warn = @import("std").debug.warn; | ... | @@ -5580,13 +5776,13 @@ const warn = @import("std").debug.warn; |
| 5580 | | 5776 | |
| 5581 | const num1 = blk: { | 5777 | const num1 = blk: { |
| 5582 | var val1: i32 = 99; | 5778 | var val1: i32 = 99; |
| 5583 | @compileLog("comptime val1 = ", val1); | 5779 | @compileLog("comptime val1 = ", val1); |
| 5584 | val1 = val1 + 1; | 5780 | val1 = val1 + 1; |
| 5585 | break :blk val1; | 5781 | break :blk val1; |
| 5586 | }; | 5782 | }; |
| 5587 | | 5783 | |
| 5588 | test "main" { | 5784 | test "main" { |
| 5589 | @compileLog("comptime in main"); | 5785 | @compileLog("comptime in main"); |
| 5590 | | 5786 | |
| 5591 | warn("Runtime in main, num1 = {}.\n", num1); | 5787 | warn("Runtime in main, num1 = {}.\n", num1); |
| 5592 | } | 5788 | } |
| ... | @@ -5596,10 +5792,10 @@ test "main" { | ... | @@ -5596,10 +5792,10 @@ test "main" { |
| 5596 | will ouput: | 5792 | will ouput: |
| 5597 | </p> | 5793 | </p> |
| 5598 | <p> | 5794 | <p> |
| 5599 | If all {#syntax#}@compileLog{#endsyntax#} calls are removed or | 5795 | If all {#syntax#}@compileLog{#endsyntax#} calls are removed or |
| 5600 | not encountered by analysis, the | 5796 | not encountered by analysis, the |
| 5601 | program compiles successfully and the generated executable prints: | 5797 | program compiles successfully and the generated executable prints: |
| 5602 | </p> | 5798 | </p> |
| 5603 | {#code_begin|test#} | 5799 | {#code_begin|test#} |
| 5604 | const warn = @import("std").debug.warn; | 5800 | const warn = @import("std").debug.warn; |
| 5605 | | 5801 | |
| ... | @@ -6425,7 +6621,7 @@ fn List(comptime T: type) type { | ... | @@ -6425,7 +6621,7 @@ fn List(comptime T: type) type { |
| 6425 | <p> | 6621 | <p> |
| 6426 | When {#syntax#}@This(){#endsyntax#} is used at global scope, it returns a reference to the | 6622 | When {#syntax#}@This(){#endsyntax#} is used at global scope, it returns a reference to the |
| 6427 | current import. There is a proposal to remove the import type and use an empty struct | 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 | <a href="https://github.com/ziglang/zig/issues/1047">#1047</a> for details. | 6625 | <a href="https://github.com/ziglang/zig/issues/1047">#1047</a> for details. |
| 6430 | </p> | 6626 | </p> |
| 6431 | {#header_close#} | 6627 | {#header_close#} |
| ... | @@ -7560,7 +7756,7 @@ const c = @cImport({ | ... | @@ -7560,7 +7756,7 @@ const c = @cImport({ |
| 7560 | {#link|Undefined Behavior#} occurs if the address is 0. | 7756 | {#link|Undefined Behavior#} occurs if the address is 0. |
| 7561 | </li> | 7757 | </li> |
| 7562 | <li>Allows address 0. On non-freestanding targets, dereferencing address 0 is safety-checked | 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 | null, just like {#syntax#}?usize{#endsyntax#}. Note that creating an optional C pointer | 7760 | null, just like {#syntax#}?usize{#endsyntax#}. Note that creating an optional C pointer |
| 7565 | is unnecessary as one can use normal {#link|Optional Pointers#}. | 7761 | is unnecessary as one can use normal {#link|Optional Pointers#}. |
| 7566 | </li> | 7762 | </li> |