I’m making Zig bindings to the Nix evaluator, and I have a function type that I need to pass that has this C signature:
typedef void(* nix_get_string_callback) (const char *start, unsigned int n, void *user_data);
Which gets translated to this after I @cImport
the header containing this definition:
const nix_get_string_callback = ?*const fn ([*c]const u8, c_uint, ?*anyopaque) callconv(.C) void
I don’t quite know how I would be able to use this; I’m able to define a function with the same signature, but I don’t know how to cast the ?*anyopaque
pointer to the C type that I need (which would be [*c]const u8
) in order to dereference it, since you can’t dereference an *anyopaque
. How should I go about implementing a function with this signature?
Not quite sure it will be helpful, but I am using little util function which looks like this:
pub fn opaqPtrTo(ptr: ?*anyopaque, comptime T: type) T {
return @ptrCast(@alignCast(ptr));
}
and then everywhere when I need to cast ?*anyopaque
to something special:
// me.data is ?*anyopaque, WorkerData is some struct
var wd = util.opaqPtrTo(me.data, *WorkerData);
Ah yeah I tried this, but when I tried to @alignCast the resulting pointer, it detected incorrect alignment coming from the cast and panicked.
The original function I tried to make to just assign the opaque pointer some data coming from a C string was this:
fn get_unowned_string_callback(str: [*c]const u8, len: c_uint, data: ?*anyopaque) callconv(.C) void {
_ = len;
const output_ptr: [*c][*c]const u8 = @ptrCast(@alignCast(data));
output_ptr.* = str;
}
Is there a way I can do this while preserving the correct alignment? The type of the pointer I want to assign it to is a char**
or [*c][*c]const u8
on the C side.
Shouldn’t it be just [*c]const u8
? What are you passing to get_unowned_string_callback()
as a 3rd parameter?
BTW, here is written that a c-pointer, in particular:
- Does not support Zig-only pointer attributes such as alignment. Use normal Pointers please!
Shouldn’t it be just [*c]const u8
? What are you passing to get_unowned_string_callback()
as a 3rd parameter?
I thought so too at first, but the pointer I’m passing to this function is a way of retrieving a const char* pointer. I should probably provide more context on why I’m doing this.
The function that I need to pass this function to is this:
nix_err nix_get_string(nix_c_context* context, const Value* value, nix_get_string_callback, callback, void* user_data);
Where I’m attempting to retrieve the value that was given to me by the Nix evaluator (stored in the *start
param) and put its value into the *user_data
variable, unmodified. Seeing that Zig alignment is not possible with C pointers (makes sense), though, does that mean that I can’t cast an ?*anyopaque
pointer to a C-style [*c]
pointer at all, and I should just drop into C code to write this callback or something like that?
Since you pass char**
([*c][*c]u8
) to void*
(?*anyopaque
) the following must work:
export fn callback(start: [*c]const u8, n: c_uint, data: ?*align(@alignOf([*][*]u8)) anyopaque) callconv(.C) void {
const ptr: [*c][*c]u8 = @ptrCast(@alignCast(data));
...
}
Sorry for not responding to this for a while. I upgraded my project to use 0.12.0 from 0.11.0 recently, and finally came up with the following solution to my problem based on the help given here:
const cstr = @cImport({
@cInclude("string.h");
});
fn owned_string_callback(start: [*c]const u8, n: c_uint, data: ?*anyopaque) callconv(.C) void {
_ = n;
const ptr: [*c][*c]u8 = @ptrCast(@alignCast(data));
ptr.* = cstr.strdup(start);
}
And used it like so:
var buf: [*c]u8 = undefined;
const err = libnix.nix_get_string(context.context, self.value, owned_string_callback, @ptrCast(&buf));
I guess it was just not playing well with 0.11.0 for some weird reason. Sorry for not providing enough context initially, and thanks for the help! I appreciate it :}
1 Like