Reputation: 301
I have the following in Zig
const std = @import("std");
var messages = [2]*[]u8{undefined, undefined};
pub fn main() !void {
// Allocate some strings
const msg1 = "First message";
const msg2 = "Second message has different length";
const allocator = std.heap.page_allocator;
const msg1_ptr = try allocator.alloc(u8, msg1.len);
defer allocator.free(msg1_ptr);
const msg2_ptr = try allocator.alloc(u8, msg2.len);
defer allocator.free(msg2_ptr);
messages[0] = @as(*[]u8, &msg1_ptr);
messages[1] = @as(*[]u8, &msg2_ptr);
It gives the following error
src/main.zig:14:30: error: expected type '*[]u8', found '*const []u8'
messages[0] = @as(*[]u8, &msg1_ptr);
^~~~~~~~~
src/main.zig:14:30: note: cast discards const qualifier
referenced by:
callMain: /usr/local/Cellar/zig/0.13.0/lib/zig/std/start.zig:524:32
callMainWithArgs: /usr/local/Cellar/zig/0.13.0/lib/zig/std/start.zig:482:12
remaining reference traces hidden; use '-freference-trace' to see all reference traces
To fix it, it was enough to change the const to var for the pointers
var msg1_ptr = try allocator.alloc(u8, msg1.len);
defer allocator.free(msg1_ptr);
var msg2_ptr = try allocator.alloc(u8, msg2.len);
defer allocator.free(msg2_ptr);
Why does a const pointer not cast to a const-agnostic pointer, but changing it to var is valid? Is it because const implies immutable, but var does not so has less restrictions? Does that mean const pointers can never be cast?
Upvotes: 0
Views: 483
Reputation: 6486
Is it because const implies immutable, but var does not so has less restrictions?
The const on a local variable means that after the initialization the variable's value will not change. Technically, you could cast away the const and try to change the variable, but its bytes might be in read-only memory.
In this case, msg1_ptr
is a slice ([]u8
), which is a fat pointer - it contains the pointer to the data and the length. The const
implies that the slice itself cannot change, but the data is not declared as const (it is u8
, not const u8
), so it can change.
By taking an address of msg1_ptr
, you get a const pointer. A const pointer implies that the memory will be read, but not changed / written to. For example, functions that want to read something by a pointer, but not change it, will typically declare the argument as const. Take std.mem.indexOf
as an example:
fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize
Why does a const pointer not cast to a const-agnostic pointer, but changing it to var is valid?
@as
is for type coercion. It does not cast types.
Switching from const
to var
is the correct solution here. If you don't want it to be const, don't declare it as const in the first place.
Does that mean const pointers can never be cast?
The @constCast
can be used to remove the const qualifier from a pointer. But you should only use it in exceptional cases.
Upvotes: 1