Reputation: 13710
Trying to use a Zig library expecting a string... but I get a string buffer from a C library.
That means that I need to pass a value of type [*c]u8
to a function that accepts [:0]const u8
.
How to do that?
I found this way so far:
const buffer: [*c]u8 = callC();
const str = std.mem.span(@ptrCast([*:0]const u8, buffer));
Which looks more complicated than it should (and makes a copy??).
The Zig docs says that:
String literals are const pointers to null-terminated arrays of u8.
So I thought they are compatible C strings and a very simple cast like @as([*:0]const u8, buffer)
should suffice?
Upvotes: 10
Views: 8796
Reputation: 3573
Which looks more complicated than it should (and makes a copy??).
So I thought they are compatible C strings and a very simple cast like @as([*:0]const u8, buffer) should suffice?
The issue here is that there is a difference between [*:0]u8
and [:0]u8
[*:0]u8
is a pointer with an unknown size ending in a 0
. To determine its length, you have to loop over it and find where it ends.[:0]u8
is a slice containing a pointer and a length. You can think of it like struct {ptr: [*:0]u8, len: usize}
. This allows code using it to immediately know its length without having to loop over it.@pointerCast
is not required to convert from a [*c]u8
to a [*:0]u8
:
const std = @import("std");
test "convert c string to [*:0]u8" {
const c_string: [*c]const u8 = "some c string";
const as_ptr: [*:0]const u8 = c_string;
_ = as_ptr;
}
To get a zig-style string slice ([]const u8
or [:0]const u8
), you can use the standard library function std.mem.span(ptr):
const std = @import("std");
test "convert c string to zig string" {
const c_string: [*c]const u8 = "some c string";
const as_slice: [:0]const u8 = std.mem.span(c_string);
try std.testing.expectEqualStrings(as_slice, "some c string");
}
const buffer: [*c]u8 = callC(); const str = std.mem.span(@ptrCast([*:0]const u8, buffer));
Which looks more complicated than it should (and makes a copy??).
std.mem.span
does not make a copy of the string - no standard library function will make a copy of something unless you pass it an allocator.
What it does is counts the length of the string and then returns a slice of the same memory, this time including a length.
Upvotes: 16