How to emulate a C-style memcpy with @memcpy?

I’m working with a C library with a need to copy some data that has been type erased, where the library allocates and provides the size of the memory buffer, but the type of the members are opaque/the type of the array is void*.

To make it work, I’ve got these two functions lurking around in a module:

fn at(ptr: *const anyopaque, index: usize, T: type) T {
    return @as(T, @ptrFromInt(@intFromPtr(ptr) + index));
}

pub fn memcpy(dest: *anyopaque, src: *const anyopaque, n: usize) void {
    for (0..n) |i| {
        at(dest, i, *u8).* = at(src, i, *u8).*;
    }
}

Considering how simple the operation is, I can’t help but feel like Zig’s @memcpy should be able to do the copy, but I just can’t figure out how to coerce the type system into letting me.

Any help?

What about this?

@memcpy(@as([*]u8, @ptrCast(dest))[0..n], @as([*]u8, @ptrCast(src))[0..n]);
4 Likes

Thank you very much! You got me on the right track.

Can anybody with a firmer grasp on Zig’s type system explain the difference between

@as(*[n]u8, @ptrCast(dest))

and

@as([*]u8, @ptrCast(dest))[0..n]

to me?

Both seem to be pointers to arrays with n elements, so I’m wondering if there’s something subtle I’m missing that’d make a semantic difference sometimes.

If n is comptime-known they’ll reduce to the same thing. Otherwise, the second option will become a slice []u8.

4 Likes

There’s only a subtle difference.

[*]T is a many item pointer and allows pointer arithmetic
*[N]T is a single item pointer to an array and allows for a .len call

The inverse however are not true.

https://ziglang.org/documentation/master/#Pointers