| ... | ... | @@ -1504,7 +1504,46 @@ test "array initialization with function calls" { |
| 1504 | 1504 | {#see_also|for|Slices#} |
| 1505 | 1505 | {#header_close#} |
| 1506 | 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 | 1547 | const assert = @import("std").debug.assert; |
| 1509 | 1548 | |
| 1510 | 1549 | test "address of syntax" { |
| ... | ... | @@ -1515,7 +1554,7 @@ test "address of syntax" { |
| 1515 | 1554 | // Deference a pointer: |
| 1516 | 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 | 1558 | assert(@typeOf(x_ptr) == *const i32); |
| 1520 | 1559 | |
| 1521 | 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 | 1577 | ptr.* += 1; |
| 1539 | 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 | 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 | 1594 | var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; |
| 1546 | 1595 | const slice = array[2..4]; |
| 1547 | 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 | 1598 | assert(array[3] == 4); |
| 1553 | 1599 | slice[1] += 1; |
| 1554 | 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 { |
| 1558 | | // Pointers work at compile-time too, as long as you don't use |
| 1559 | | // @ptrCast. |
| 1560 | | var x: i32 = 1; |
| 1561 | | const ptr = &x; |
| 1562 | | ptr.* += 1; |
| 1563 | | x += 1; |
| 1564 | | assert(ptr.* == 3); |
| 1608 | test "comptime pointers" { |
| 1609 | comptime { |
| 1610 | var x: i32 = 1; |
| 1611 | const ptr = &x; |
| 1612 | ptr.* += 1; |
| 1613 | x += 1; |
| 1614 | 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 | 1623 | test "@ptrToInt and @intToPtr" { |
| 1568 | | // To convert an integer address into a pointer, use @intToPtr: |
| 1569 | 1624 | const ptr = @intToPtr(*i32, 0xdeadbeef); |
| 1570 | | |
| 1571 | | // To convert a pointer to an integer, use @ptrToInt: |
| 1572 | 1625 | const addr = @ptrToInt(ptr); |
| 1573 | | |
| 1574 | 1626 | assert(@typeOf(addr) == usize); |
| 1575 | 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 { |
| 1579 | | // Zig is able to do this at compile-time, as long as |
| 1580 | | // ptr is never dereferenced. |
| 1581 | | const ptr = @intToPtr(*i32, 0xdeadbeef); |
| 1582 | | const addr = @ptrToInt(ptr); |
| 1583 | | assert(@typeOf(addr) == usize); |
| 1584 | | assert(addr == 0xdeadbeef); |
| 1635 | test "comptime @intToPtr" { |
| 1636 | comptime { |
| 1637 | // Zig is able to do this at compile-time, as long as |
| 1638 | // ptr is never dereferenced. |
| 1639 | const ptr = @intToPtr(*i32, 0xdeadbeef); |
| 1640 | const addr = @ptrToInt(ptr); |
| 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 | 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 | 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 | 1657 | assert(@typeOf(mmio_ptr) == *volatile u8); |
| 1596 | 1658 | } |
| 1597 | | |
| 1598 | | test "optional pointers" { |
| 1599 | | // Pointers cannot be null. If you want a null pointer, use the optional |
| 1600 | | // prefix `?` to make the pointer type optional. |
| 1601 | | var ptr: ?*i32 = null; |
| 1602 | | |
| 1603 | | var x: i32 = 1; |
| 1604 | | ptr = &x; |
| 1605 | | |
| 1606 | | assert(ptr.?.* == 1); |
| 1607 | | |
| 1608 | | // Optional pointers are the same size as normal pointers, because pointer |
| 1609 | | // value 0 is used as the null value. |
| 1610 | | assert(@sizeOf(?*i32) == @sizeOf(*i32)); |
| 1611 | | } |
| 1659 | {#code_end#} |
| 1660 | <p> |
| 1661 | Note that {#syntax#}volatile{#endsyntax#} is unrelated to concurrency and {#link|Atomics#}. |
| 1662 | If you see code that is using {#syntax#}volatile{#endsyntax#} for something other than Memory Mapped |
| 1663 | Input/Output, it is probably a bug. |
| 1664 | </p> |
| 1665 | {#header_close#} |
| 1666 | <p> |
| 1667 | To convert one pointer type to another, use {#link|@ptrCast#}. This is an unsafe |
| 1668 | operation that Zig cannot protect you against. Use {#syntax#}@ptrCast{#endsyntax#} only when other |
| 1669 | conversions are not possible. |
| 1670 | </p> |
| 1671 | {#code_begin|test#} |
| 1672 | const assert = @import("std").debug.assert; |
| 1612 | 1673 | |
| 1613 | 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 | 1675 | const bytes align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12 }; |
| 1618 | 1676 | const u32_ptr = @ptrCast(*const u32, &bytes); |
| 1619 | 1677 | assert(u32_ptr.* == 0x12121212); |
| ... | ... | @@ -1714,19 +1772,6 @@ fn foo(bytes: []u8) u32 { |
| 1714 | 1772 | } |
| 1715 | 1773 | {#code_end#} |
| 1716 | 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 | 1775 | {#header_close#} |
| 1731 | 1776 | {#header_open|Slices#} |
| 1732 | 1777 | {#code_begin|test_safety|index out of bounds#} |
| ... | ... | @@ -3816,6 +3861,28 @@ test "optional type" { |
| 3816 | 3861 | </p> |
| 3817 | 3862 | {#code_begin|syntax#} |
| 3818 | 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 | 3886 | {#code_end#} |
| 3820 | 3887 | {#header_close#} |
| 3821 | 3888 | {#header_close#} |