#Zig style string to c string?
1 messages · Page 1 of 1 (latest)
i think it should be coerced automatically?
given you are not also passing along the length of the string this C function likely expects the string to be null terminated, which []const u8 is not.
const std = @import("std");
test "[]const u8 to [*c]const u8 - with terminator" {
var arenabuf = std.heap.ArenaAllocator.init(std.testing.allocator);
defer arenabuf.deinit();
const arena = arenabuf.allocator();
const raw = "hellobadbytes";
const s1: []const u8 = raw[0..5]; // "hello"
const s2: [*c]const u8 = try arena.dupeZ(u8, s1); // "hello\0"
try std.testing.expectEqual(0, s2[s1.len]);
const s3 = try std.fmt.allocPrint(arena, "{s}", .{s2}); // "hello", printing without badbytes
try std.testing.expectEqualStrings(s1, s3);
// other direction:
const s4: [*c]const u8 = raw.ptr;
const s5 = try std.fmt.allocPrint(arena, "{s}", .{s4});
try std.testing.expectEqualStrings(raw, s5);
// you can leave [*c]T to foreign signatures and use more restrained types
// in your own code
const s6: [*:0]const u8 = raw.ptr;
const s7: [*c]const u8 = s6;
_ = s7;
}
NB. the list of things [*c] pointers can do, https://ziglang.org/documentation/0.13.0/#C-Pointers
vs. the much shorter lists for other pointer types:
https://ziglang.org/documentation/0.13.0/#Pointers
more important: don't use C pointers, use the correct pointer type; they will coerce to a C pointer at the translated function boundary and you can coerce a c pointer to any zig pointer type
https://github.com/ziglang/zig/issues/2984 using C pointers in not translated code will become a compile error at some point
To add another example to this, I have the below in my code that uses SDL (a C library):
const file_path_z = try std.fmt.allocPrint(allocator, "assets/{s}.png", .{@tagName(obj_type)});
const file_path_c: [:0]u8 = try allocator.dupeZ(u8, file_path_z);
defer allocator.free(file_path_z);
defer allocator.free(file_path_c);
const surface = c.IMG_Load(file_path_c) orelse {
c.SDL_Log("Could not load image %s\n", c.SDL_GetError());
return error.SDLInitFailed;
};```
I've never seen allocPrint used for something like this lol. I would recommend std.mem.span (along with allocator.dupe if you really do need to duplicate it)
I believe allocPrintZ exists, which will remove the need to dupeZ afterwards :)
Didn't know about that - will clean up some ugliness. Thanks!