about summary refs log tree commit diff
path: root/lang/zig/pointers.zig
blob: 92c0d9df83a88dcb5afd95cd9ceabb46916b2d33 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
const std = @import("std");
const expect = std.testing.expect;
const bytesAsSlice = std.mem.bytesAsSlice;

test "address of syntax" {
    // Get the address of a variable:
    const x: i32 = 1234;
    const x_ptr = &x;

    // Dereference a pointer:
    expect(x_ptr.* == 1234);

    // When you get the address of a const variable,
    // you get a const pointer to a single item.
    expect(@TypeOf(x_ptr) == *const i32);

    // If you want to mutate the value,
    // you'd need an address of a mutable variable:
    var y: i32 = 5678;
    const y_ptr = &y;
    expect(@TypeOf(y_ptr) == *i32);
    y_ptr.* += 1;
    expect(y_ptr.* == 5679);
}

test "pointer array access" {
    // Taking an address of an individual element gives a
    // pointer to a single item. This kind of pointer
    // does not support pointer arithmetic.
    var array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    const ptr = &array[2];
    expect(@TypeOf(ptr) == *u8);

    expect(array[2] == 3);
    ptr.* += 1;
    expect(array[2] == 4);
}

test "pointer slicing" {
    var array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    const slice = array[2..4];
    expect(slice.len == 2);

    expect(array[3] == 4);
    slice[1] += 1;
    expect(array[3] == 5);
}

test "comptime pointers" {
    comptime {
        var x: i32 = 1;
        const ptr = &x;
        ptr.* += 1;
        x += 1;
        expect(ptr.* == 3);
    }
}

test "@ptrToInt and @intToPtr" {
    const ptr = @intToPtr(*i32, 0xdeadbee0);
    const addr = @ptrToInt(ptr);
    expect(@TypeOf(addr) == usize);
    expect(addr == 0xdeadbee0);
}

test "comptime @intToPtr" {
    comptime {
        const ptr = @intToPtr(*i32, 0xdeadbee0);
        const addr = @ptrToInt(ptr);
        expect(@TypeOf(addr) == usize);
        expect(addr == 0xdeadbee0);
    }
}

test "volatile" {
    const mmio_ptr = @intToPtr(*volatile u8, 0x12345678);
    expect(@TypeOf(mmio_ptr) == *volatile u8);
}

test "pointer casting" {
    const bytes align(@alignOf(u32)) = [_]u8{ 0x12 } ** 4;
    const u32_ptr = @ptrCast(*const u32, &bytes);
    expect(u32_ptr.* == 0x12121212);

    // Even this example is contrived,
    // there are better ways to do the above than pointer casting.
    // For example, using a slice narrowing cast:
    const u32_value = bytesAsSlice(u32, bytes[0..])[0];
    expect(u32_value == 0x12121212);

    // And even another way, the most straightforward way to do it:
    expect(@bitCast(u32, bytes) == 0x12121212);
}