I'm having trouble passing a function pointer into a C API.
The Tetris example demonstrates passing Zig function to a C API for use as a callback.
However, when I attempt to perform the same (calling into GNU Guile Scheme), I receive:
error: expected type '?*c_void', found '*const extern fn(?[*]struct_scm_unused_struct) ?[*]struct_scm_unused_struct'
fn real_fact(x: c_int) c_int {
if(x == 1) {
return 1;
} else {
return x * real_fact(x-1);
}
}
extern fn c_fact(arg: SCM) SCM {
const c_arg: c_int = scm_to_int(arg);
return scm_from_int( real_fact(c_arg));
}
pub fn main() void {
scm_c_define_gsubr(c"c-fact", 1, 0, 0, c_fact);
}
I've attempted to use &c_fact instead of c_fact. No luck.
I've attempted to use @ptrCast(*c_void, c_fact), but this results in "cast discards const qualifier." Not sure how to discard the const qualifier of a fn.
One last thought: I've only seen void callback fns succeed so far. Could it be that my case is failing because c_fact has a return type?
Thanks again for the great work. Enjoying the language quite a bit so far.
If you really need to discard a const from a pointer then the following way will work:
pub fn main() void {
var c_fact_var = @intToPtr(?*c_void, @ptrToInt(c_fact));
_ = scm_c_define_gsubr(c"c-fact", 1, 0, 0, c_fact_var);
}
I don't think there is much better here since the function requiring a *c_void type is fairly limiting. If there are stronger guarantees on the api (actually doesn't modify values) you could declare the function yourself with a *const c_void or manually use zig translate-c and modify as needed, then the ptrCast should work as expected.
The return value shouldn't matter here.
For completeness, note that casting a C function pointer to a void pointer is not necessarily defined, and therefore not portable. It is reasonable to call this required hack a bug in the C API.
OK, awesome. Thanks much for the solutions!
I ended up switching to D for my project, but have very much enjoyed my use of Zig and I think you guys are on to something. Very sorry to jump in, ask this question, then bounce. :sweat:
I'll likely be back at some point. I think that when craving more safety in systems programming, Zig is much more appealing than Rust. Keep it up. :+1: :bowing_man:
Most helpful comment
If you really need to discard a const from a pointer then the following way will work:
I don't think there is much better here since the function requiring a
*c_voidtype is fairly limiting. If there are stronger guarantees on the api (actually doesn't modify values) you could declare the function yourself with a*const c_voidor manually usezig translate-cand modify as needed, then theptrCastshould work as expected.The return value shouldn't matter here.