authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-10-04 22:51:36-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-10-04 22:51:36-04:00
log8d6601d7ce6adb22103892f50176e4e2a60fe2fc
tree4469f79d1a4e6b1ed604120f12ecf3659aef01d7
parentd07413f9b77a1e8e27ba09d2183ba5d614268c76
signature Commit is signed but in an unrecognized format.

improve pointer documentation

closes #1630

1 files changed, 130 insertions(+), 63 deletions(-)

doc/langref.html.in+130-63
...@@ -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#}
1508const assert = @import("std").debug.assert;1547const assert = @import("std").debug.assert;
15091548
1510test "address of syntax" {1549test "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);
15171556
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);
15201559
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#}
1591const assert = @import("std").debug.assert;
15411592
1542test "pointer slicing" {1593test "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);
15481597
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#}
1606const assert = @import("std").debug.assert;
15561607
1557comptime {1608test "comptime pointers" {
1558 // Pointers work at compile-time too, as long as you don't use1609 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#}
1621const assert = @import("std").debug.assert;
15661622
1567test "@ptrToInt and @intToPtr" {1623test "@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#}
1633const assert = @import("std").debug.assert;
15771634
1578comptime {1635test "comptime @intToPtr" {
1579 // Zig is able to do this at compile-time, as long as1636 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#}
1653const assert = @import("std").debug.assert;
15861654
1587test "volatile" {1655test "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}
15971659 {#code_end#}
1598test "optional pointers" {1660 <p>
1599 // Pointers cannot be null. If you want a null pointer, use the optional1661 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.
16021664 </p>
1603 var x: i32 = 1;1665 {#header_close#}
1604 ptr = &x;1666 <p>
16051667 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
16071669 conversions are not possible.
1608 // Optional pointers are the same size as normal pointers, because pointer1670 </p>
1609 // value 0 is used as the null value.1671 {#code_begin|test#}
1610 assert(@sizeOf(?*i32) == @sizeOf(*i32));1672const assert = @import("std").debug.assert;
1611}
16121673
1613test "pointer casting" {1674test "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#}
3818const optional_value: ?i32 = null; 3863const 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#}
3870const assert = @import("std").debug.assert;
3871
3872test "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#}