| ... | @@ -1504,7 +1504,46 @@ test "array initialization with function calls" { | ... | @@ -1504,7 +1504,46 @@ test "array initialization with function calls" { |
| 1504 | {#see_also|for|Slices#} | 1504 | {#see_also|for|Slices#} |
| 1505 | {#header_close#} | 1505 | {#header_close#} |
| 1506 | {#header_open|Pointers#} | 1506 | {#header_open|Pointers#} |
| 1507 | {#code_begin|test#} | 1507 | <p> |
| | 1508 | Zig has two kinds of pointers: |
| | 1509 | </p> |
| | 1510 | <ul> |
| | 1511 | <li>{#syntax#}*T{#endsyntax#} - pointer to exactly one item. |
| | 1512 | <ul> |
| | 1513 | <li>Supports deref syntax: {#syntax#}ptr.*{#endsyntax#}</li> |
| | 1514 | </ul> |
| | 1515 | </li> |
| | 1516 | <li>{#syntax#}[*]T{#endsyntax#} - pointer to unknown number of items. |
| | 1517 | <ul> |
| | 1518 | <li>Supports index syntax: {#syntax#}ptr[i]{#endsyntax#}</li> |
| | 1519 | <li>Supports slice syntax: {#syntax#}ptr[start..end]{#endsyntax#}</li> |
| | 1520 | <li>Supports pointer arithmetic: {#syntax#}ptr + x{#endsyntax#}, {#syntax#}ptr - x{#endsyntax#}</li> |
| | 1521 | <li>{#syntax#}T{#endsyntax#} must have a known size, which means that it cannot be |
| | 1522 | {#syntax#}c_void{#endsyntax#} or any other {#link|@OpaqueType#}.</li> |
| | 1523 | </ul> |
| | 1524 | </li> |
| | 1525 | </ul> |
| | 1526 | <p>These types are closely related to {#link|Arrays#} and {#link|Slices#}:</p> |
| | 1527 | <ul> |
| | 1528 | <li>{#syntax#}*[N]T{#endsyntax#} - pointer to N items, same as single-item pointer to array. |
| | 1529 | <ul> |
| | 1530 | <li>Supports index syntax: {#syntax#}array_ptr[i]{#endsyntax#}</li> |
| | 1531 | <li>Supports slice syntax: {#syntax#}array_ptr[start..end]{#endsyntax#}</li> |
| | 1532 | <li>Supports len property: {#syntax#}array_ptr.len{#endsyntax#}</li> |
| | 1533 | </ul> |
| | 1534 | </li> |
| | 1535 | </ul> |
| | 1536 | <ul> |
| | 1537 | <li>{#syntax#}[]T{#endsyntax#} - pointer to runtime-known number of items. |
| | 1538 | <ul> |
| | 1539 | <li>Supports index syntax: {#syntax#}slice[i]{#endsyntax#}</li> |
| | 1540 | <li>Supports slice syntax: {#syntax#}slice[start..end]{#endsyntax#}</li> |
| | 1541 | <li>Supports len property: {#syntax#}slice.len{#endsyntax#}</li> |
| | 1542 | </ul> |
| | 1543 | </li> |
| | 1544 | </ul> |
| | 1545 | <p>Use {#syntax#}&x{#endsyntax#} to obtain a single-item pointer:</p> |
| | 1546 | {#code_begin|test#} |
| 1508 | const assert = @import("std").debug.assert; | 1547 | const assert = @import("std").debug.assert; |
| 1509 | | 1548 | |
| 1510 | test "address of syntax" { | 1549 | test "address of syntax" { |
| ... | @@ -1515,7 +1554,7 @@ test "address of syntax" { | ... | @@ -1515,7 +1554,7 @@ test "address of syntax" { |
| 1515 | // Deference a pointer: | 1554 | // Deference a pointer: |
| 1516 | assert(x_ptr.* == 1234); | 1555 | assert(x_ptr.* == 1234); |
| 1517 | | 1556 | |
| 1518 | // When you get the address of a const variable, you get a const pointer. | 1557 | // When you get the address of a const variable, you get a const pointer to a single item. |
| 1519 | assert(@typeOf(x_ptr) == *const i32); | 1558 | assert(@typeOf(x_ptr) == *const i32); |
| 1520 | | 1559 | |
| 1521 | // If you want to mutate the value, you'd need an address of a mutable variable: | 1560 | // If you want to mutate the value, you'd need an address of a mutable variable: |
| ... | @@ -1538,82 +1577,101 @@ test "pointer array access" { | ... | @@ -1538,82 +1577,101 @@ test "pointer array access" { |
| 1538 | ptr.* += 1; | 1577 | ptr.* += 1; |
| 1539 | assert(array[2] == 4); | 1578 | assert(array[2] == 4); |
| 1540 | } | 1579 | } |
| | 1580 | {#code_end#} |
| | 1581 | <p> |
| | 1582 | In Zig, we prefer slices over pointers to null-terminated arrays. |
| | 1583 | You can turn an array or pointer into a slice using slice syntax. |
| | 1584 | </p> |
| | 1585 | <p> |
| | 1586 | Slices have bounds checking and are therefore protected |
| | 1587 | against this kind of undefined behavior. This is one reason |
| | 1588 | we prefer slices to pointers. |
| | 1589 | </p> |
| | 1590 | {#code_begin|test#} |
| | 1591 | const assert = @import("std").debug.assert; |
| 1541 | | 1592 | |
| 1542 | test "pointer slicing" { | 1593 | test "pointer slicing" { |
| 1543 | // In Zig, we prefer slices over pointers to null-terminated arrays. | | |
| 1544 | // You can turn an array into a slice using slice syntax: | | |
| 1545 | var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; | 1594 | var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; |
| 1546 | const slice = array[2..4]; | 1595 | const slice = array[2..4]; |
| 1547 | assert(slice.len == 2); | 1596 | assert(slice.len == 2); |
| 1548 | | 1597 | |
| 1549 | // Slices have bounds checking and are therefore protected | | |
| 1550 | // against this kind of undefined behavior. This is one reason | | |
| 1551 | // we prefer slices to pointers. | | |
| 1552 | assert(array[3] == 4); | 1598 | assert(array[3] == 4); |
| 1553 | slice[1] += 1; | 1599 | slice[1] += 1; |
| 1554 | assert(array[3] == 5); | 1600 | assert(array[3] == 5); |
| 1555 | } | 1601 | } |
| | 1602 | {#code_end#} |
| | 1603 | <p>Pointers work at compile-time too, as long as the code does not depend on |
| | 1604 | an undefined memory layout:</p> |
| | 1605 | {#code_begin|test#} |
| | 1606 | const assert = @import("std").debug.assert; |
| 1556 | | 1607 | |
| 1557 | comptime { | 1608 | test "comptime pointers" { |
| 1558 | // Pointers work at compile-time too, as long as you don't use | 1609 | comptime { |
| 1559 | // @ptrCast. | 1610 | var x: i32 = 1; |
| 1560 | var x: i32 = 1; | 1611 | const ptr = &x; |
| 1561 | const ptr = &x; | 1612 | ptr.* += 1; |
| 1562 | ptr.* += 1; | 1613 | x += 1; |
| 1563 | x += 1; | 1614 | assert(ptr.* == 3); |
| 1564 | assert(ptr.* == 3); | 1615 | } |
| 1565 | } | 1616 | } |
| | 1617 | {#code_end#} |
| | 1618 | <p>To convert an integer address into a pointer, use {#syntax#}@intToPtr{#endsyntax#}. |
| | 1619 | To convert a pointer to an integer, use {#syntax#}@ptrToInt{#endsyntax#}:</p> |
| | 1620 | {#code_begin|test#} |
| | 1621 | const assert = @import("std").debug.assert; |
| 1566 | | 1622 | |
| 1567 | test "@ptrToInt and @intToPtr" { | 1623 | test "@ptrToInt and @intToPtr" { |
| 1568 | // To convert an integer address into a pointer, use @intToPtr: | | |
| 1569 | const ptr = @intToPtr(*i32, 0xdeadbeef); | 1624 | const ptr = @intToPtr(*i32, 0xdeadbeef); |
| 1570 | | | |
| 1571 | // To convert a pointer to an integer, use @ptrToInt: | | |
| 1572 | const addr = @ptrToInt(ptr); | 1625 | const addr = @ptrToInt(ptr); |
| 1573 | | | |
| 1574 | assert(@typeOf(addr) == usize); | 1626 | assert(@typeOf(addr) == usize); |
| 1575 | assert(addr == 0xdeadbeef); | 1627 | assert(addr == 0xdeadbeef); |
| 1576 | } | 1628 | } |
| | 1629 | {#code_end#} |
| | 1630 | <p>Zig is able to preserve memory addresses in comptime code, as long as |
| | 1631 | the pointer is never dereferenced:</p> |
| | 1632 | {#code_begin|test#} |
| | 1633 | const assert = @import("std").debug.assert; |
| 1577 | | 1634 | |
| 1578 | comptime { | 1635 | test "comptime @intToPtr" { |
| 1579 | // Zig is able to do this at compile-time, as long as | 1636 | comptime { |
| 1580 | // ptr is never dereferenced. | 1637 | // Zig is able to do this at compile-time, as long as |
| 1581 | const ptr = @intToPtr(*i32, 0xdeadbeef); | 1638 | // ptr is never dereferenced. |
| 1582 | const addr = @ptrToInt(ptr); | 1639 | const ptr = @intToPtr(*i32, 0xdeadbeef); |
| 1583 | assert(@typeOf(addr) == usize); | 1640 | const addr = @ptrToInt(ptr); |
| 1584 | assert(addr == 0xdeadbeef); | 1641 | assert(@typeOf(addr) == usize); |
| | 1642 | assert(addr == 0xdeadbeef); |
| | 1643 | } |
| 1585 | } | 1644 | } |
| | 1645 | {#code_end#} |
| | 1646 | {#see_also|Optional Pointers#} |
| | 1647 | {#header_open|volatile#} |
| | 1648 | <p>Loads and stores are assumed to not have side effects. If a given load or store |
| | 1649 | should have side effects, such as Memory Mapped Input/Output (MMIO), use {#syntax#}volatile{#endsyntax#}. |
| | 1650 | In the following code, loads and stores with {#syntax#}mmio_ptr{#endsyntax#} are guaranteed to all happen |
| | 1651 | and in the same order as in source code:</p> |
| | 1652 | {#code_begin|test#} |
| | 1653 | const assert = @import("std").debug.assert; |
| 1586 | | 1654 | |
| 1587 | test "volatile" { | 1655 | test "volatile" { |
| 1588 | // In Zig, loads and stores are assumed to not have side effects. | | |
| 1589 | // If a given load or store should have side effects, such as | | |
| 1590 | // Memory Mapped Input/Output (MMIO), use `volatile`: | | |
| 1591 | const mmio_ptr = @intToPtr(*volatile u8, 0x12345678); | 1656 | const mmio_ptr = @intToPtr(*volatile u8, 0x12345678); |
| 1592 | | | |
| 1593 | // Now loads and stores with mmio_ptr are guaranteed to all happen | | |
| 1594 | // and in the same order as in source code. | | |
| 1595 | assert(@typeOf(mmio_ptr) == *volatile u8); | 1657 | assert(@typeOf(mmio_ptr) == *volatile u8); |
| 1596 | } | 1658 | } |
| 1597 | | 1659 | {#code_end#} |
| 1598 | test "optional pointers" { | 1660 | <p> |
| 1599 | // Pointers cannot be null. If you want a null pointer, use the optional | 1661 | Note that {#syntax#}volatile{#endsyntax#} is unrelated to concurrency and {#link|Atomics#}. |
| 1600 | // prefix `?` to make the pointer type optional. | 1662 | If you see code that is using {#syntax#}volatile{#endsyntax#} for something other than Memory Mapped |
| 1601 | var ptr: ?*i32 = null; | 1663 | Input/Output, it is probably a bug. |
| 1602 | | 1664 | </p> |
| 1603 | var x: i32 = 1; | 1665 | {#header_close#} |
| 1604 | ptr = &x; | 1666 | <p> |
| 1605 | | 1667 | To convert one pointer type to another, use {#link|@ptrCast#}. This is an unsafe |
| 1606 | assert(ptr.?.* == 1); | 1668 | operation that Zig cannot protect you against. Use {#syntax#}@ptrCast{#endsyntax#} only when other |
| 1607 | | 1669 | conversions are not possible. |
| 1608 | // Optional pointers are the same size as normal pointers, because pointer | 1670 | </p> |
| 1609 | // value 0 is used as the null value. | 1671 | {#code_begin|test#} |
| 1610 | assert(@sizeOf(?*i32) == @sizeOf(*i32)); | 1672 | const assert = @import("std").debug.assert; |
| 1611 | } | | |
| 1612 | | 1673 | |
| 1613 | test "pointer casting" { | 1674 | test "pointer casting" { |
| 1614 | // To convert one pointer type to another, use @ptrCast. This is an unsafe | | |
| 1615 | // operation that Zig cannot protect you against. Use @ptrCast only when other | | |
| 1616 | // conversions are not possible. | | |
| 1617 | const bytes align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12 }; | 1675 | const bytes align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12 }; |
| 1618 | const u32_ptr = @ptrCast(*const u32, &bytes); | 1676 | const u32_ptr = @ptrCast(*const u32, &bytes); |
| 1619 | assert(u32_ptr.* == 0x12121212); | 1677 | assert(u32_ptr.* == 0x12121212); |
| ... | @@ -1714,19 +1772,6 @@ fn foo(bytes: []u8) u32 { | ... | @@ -1714,19 +1772,6 @@ fn foo(bytes: []u8) u32 { |
| 1714 | } | 1772 | } |
| 1715 | {#code_end#} | 1773 | {#code_end#} |
| 1716 | {#header_close#} | 1774 | {#header_close#} |
| 1717 | {#header_open|Type Based Alias Analysis#} | | |
| 1718 | <p>Zig uses Type Based Alias Analysis (also known as Strict Aliasing) to | | |
| 1719 | perform some optimizations. This means that pointers of different types must | | |
| 1720 | not alias the same memory, with the exception of {#syntax#}u8{#endsyntax#}. Pointers to | | |
| 1721 | {#syntax#}u8{#endsyntax#} can alias any memory. | | |
| 1722 | </p> | | |
| 1723 | <p>As an example, this code produces undefined behavior:</p> | | |
| 1724 | <pre>{#syntax#}@ptrCast(*u32, f32(12.34)).*{#endsyntax#}</pre> | | |
| 1725 | <p>Instead, use {#link|@bitCast#}: | | |
| 1726 | <pre>{#syntax#}@bitCast(u32, f32(12.34)){#endsyntax#}</pre> | | |
| 1727 | <p>As an added benefit, the {#syntax#}@bitCast{#endsyntax#} version works at compile-time.</p> | | |
| 1728 | {#see_also|Slices|Memory#} | | |
| 1729 | {#header_close#} | | |
| 1730 | {#header_close#} | 1775 | {#header_close#} |
| 1731 | {#header_open|Slices#} | 1776 | {#header_open|Slices#} |
| 1732 | {#code_begin|test_safety|index out of bounds#} | 1777 | {#code_begin|test_safety|index out of bounds#} |
| ... | @@ -3816,6 +3861,28 @@ test "optional type" { | ... | @@ -3816,6 +3861,28 @@ test "optional type" { |
| 3816 | </p> | 3861 | </p> |
| 3817 | {#code_begin|syntax#} | 3862 | {#code_begin|syntax#} |
| 3818 | const optional_value: ?i32 = null; | 3863 | const optional_value: ?i32 = null; |
| | 3864 | {#code_end#} |
| | 3865 | {#header_close#} |
| | 3866 | {#header_open|Optional Pointers#} |
| | 3867 | <p>An optional pointer is guaranteed to be the same size as a pointer. The {#syntax#}null{#endsyntax#} of |
| | 3868 | the optional is guaranteed to be address 0.</p> |
| | 3869 | {#code_begin|test#} |
| | 3870 | const assert = @import("std").debug.assert; |
| | 3871 | |
| | 3872 | test "optional pointers" { |
| | 3873 | // Pointers cannot be null. If you want a null pointer, use the optional |
| | 3874 | // prefix `?` to make the pointer type optional. |
| | 3875 | var ptr: ?*i32 = null; |
| | 3876 | |
| | 3877 | var x: i32 = 1; |
| | 3878 | ptr = &x; |
| | 3879 | |
| | 3880 | assert(ptr.?.* == 1); |
| | 3881 | |
| | 3882 | // Optional pointers are the same size as normal pointers, because pointer |
| | 3883 | // value 0 is used as the null value. |
| | 3884 | assert(@sizeOf(?*i32) == @sizeOf(*i32)); |
| | 3885 | } |
| 3819 | {#code_end#} | 3886 | {#code_end#} |
| 3820 | {#header_close#} | 3887 | {#header_close#} |
| 3821 | {#header_close#} | 3888 | {#header_close#} |