Durobot
December 8, 2023, 10:40pm
1
How would you coerce a slice to an array?
I would like to pass a (small) portion of a buffer to a function, as an array. So, I thought, why not slice it, and then coerce that slice to array, since I know the length.
The only way I have found is quite awkward:
const std = @import("std");
const native_endian = @import("builtin").target.cpu.arch.endian();
pub fn main() void
{
var buf = [_]u8 { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE };
const sl = buf[0..4];
const u = bytesToU32(@as([4]u8, @as(*[4]u8, @ptrCast(sl.ptr)).*));
std.debug.print("u = 0x{x}\n", .{ u });
}
fn bytesToU32(b: [4]u8) u32
{
if (native_endian == .big)
return b[0] | (@as(u32, b[1]) << 8) | (@as(u32, b[2]) << 16) | (@as(u32, b[3]) << 24)
else
return (@as(u32, b[0]) << 24) | (@as(u32, b[1]) << 16) | (@as(u32, b[2]) << 8) | b[3];
}
This works, but @as([4]u8, @as(*[4]u8, @ptrCast(sl.ptr)).*)
is really quite ugly.
There just has to be a better way.
Durobot
December 8, 2023, 10:51pm
3
Oh.
This reduces the coercion to @as([4]u8, sl.*)
then.
Wait, I can just use sl.*
. Brilliant!
Thank you!
3 Likes
LucasSantos91:
sl is already * [4]u8
However, sl.*
only works if sl
’s indices ([0..4]
) are comptime-known, right?
Doesn’t work if I do something like
var pos: u32 = 0;
pos = 2;
const sl = buf[(pos+0)..(pos+4)];
error: index syntax required for slice type '[]u8'
const u = bytesToU32(sl.*);
~~^~
The original ugly version does work though.
Tosti
December 9, 2023, 3:17pm
5
What about buf[pos..][0..4]
? The first subscript is a slice, but the second is a ponter to an array, because the lenth is comptime known.
3 Likes
The size must be comptime known, but the offset doesn’t need to be:
const sl = buf[pos..][0..4];
This will also produce a * [4]u8
.
2 Likes
Thank you.
Took me some time to figure out what it means, as [ ][ ]
notation looks like indexing a 2-dimensional array to my eyes.
I think I’m going to write it like (buf[pos..])[0..4]
, just for clarity.
3 Likes