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" {
15041504 {#see_also|for|Slices#}
15051505 {#header_close#}
15061506 {#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#}
15081547const assert = @import("std").debug.assert;
15091548
15101549test "address of syntax" {
......@@ -1515,7 +1554,7 @@ test "address of syntax" {
15151554 // Deference a pointer:
15161555 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.
15191558 assert(@typeOf(x_ptr) == *const i32);
15201559
15211560 // If you want to mutate the value, you'd need an address of a mutable variable:
......@@ -1538,82 +1577,101 @@ test "pointer array access" {
15381577 ptr.* += 1;
15391578 assert(array[2] == 4);
15401579}
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
15421593test "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:
15451594 var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
15461595 const slice = array[2..4];
15471596 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.
15521598 assert(array[3] == 4);
15531599 slice[1] += 1;
15541600 assert(array[3] == 5);
15551601}
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 {
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);
1608test "comptime pointers" {
1609 comptime {
1610 var x: i32 = 1;
1611 const ptr = &x;
1612 ptr.* += 1;
1613 x += 1;
1614 assert(ptr.* == 3);
1615 }
15651616}
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
15671623test "@ptrToInt and @intToPtr" {
1568 // To convert an integer address into a pointer, use @intToPtr:
15691624 const ptr = @intToPtr(*i32, 0xdeadbeef);
1570
1571 // To convert a pointer to an integer, use @ptrToInt:
15721625 const addr = @ptrToInt(ptr);
1573
15741626 assert(@typeOf(addr) == usize);
15751627 assert(addr == 0xdeadbeef);
15761628}
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 {
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);
1635test "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 }
15851644}
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
15871655test "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`:
15911656 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.
15951657 assert(@typeOf(mmio_ptr) == *volatile u8);
15961658}
1597
1598test "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#}
1672const assert = @import("std").debug.assert;
16121673
16131674test "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.
16171675 const bytes align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12 };
16181676 const u32_ptr = @ptrCast(*const u32, &bytes);
16191677 assert(u32_ptr.* == 0x12121212);
......@@ -1714,19 +1772,6 @@ fn foo(bytes: []u8) u32 {
17141772}
17151773 {#code_end#}
17161774 {#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#}
17301775 {#header_close#}
17311776 {#header_open|Slices#}
17321777 {#code_begin|test_safety|index out of bounds#}
......@@ -3816,6 +3861,28 @@ test "optional type" {
38163861 </p>
38173862 {#code_begin|syntax#}
38183863const 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}
38193886 {#code_end#}
38203887 {#header_close#}
38213888 {#header_close#}