I’m working with a c audio library miniaudio that has a callback function dataCallback
with an p_output: ?*anyopaque
parameter.
How do I go about checking the alignment and casting to the correct type which is a 32 bit floating point array?
What I have so far:
fn dataCallback(p_device: [*c]c.ma_device, p_output: ?*anyopaque, p_input: ?*const anyopaque, frame_count: c.ma_uint32) callconv(.C) void {
_ = p_input;
if (p_device.*.type == c.ma_device_type_playback) {
if (p_output) |out| {
// check pointer alignment
if (@alignOf(@TypeOf(out)) == @alignOf([*]f32)) {
// safe to cast the pointer since it's properly aligned
const output_ptr: [*]f32 = @as([*]f32, @ptrCast(out));
Not sure if my syntax is correct, but I’m getting:
error: cast increases pointer alignment
const output_ptr: [*]f32 = @as([*]f32, @ptrCast(out));
^~~~~~~~~~~~~
Thanks
I tried swapping for @alignCast
and it errored telling me to use @ptrCast
.
Then I had the strangest idea, let’s use both! 
Success!
const output_ptr = @as([*]f32, @ptrCast(@alignCast(out)));
4 Likes
Some time ago I run into similar problems and eventually I made this helper function:
pub fn opaqPtrTo(ptr: ?*anyopaque, comptime T: type) T {
return @ptrCast(@alignCast(ptr));
}
and then something like
var pd = util.opaqPtrTo(me.data, *ListenerData);
3 Likes
Well the input was a const
so. . . .
// const array = [_][]const u8{"@Cast"} ** 3; heehee
const p_input_frames = @as([*]f32, @constCast(@ptrCast(@alignCast(in))));
1 Like
The 0.11.0
release notes section on pointer casts can be helpful for understanding what’s going on here:
The builtins @addrSpaceCast
and @alignCast
would become quite cumbersome to use under this system as described, since you would now have to specify the full intermediate pointer types. Instead, pointer casts (those two builtins and @ptrCast
) are special. They combine into a single logical operation, with each builtin effectively “allowing” a particular component of the pointer to be cast rather than “performing” it. (Indeed, this may be a helpful mental model for the new cast builtins more generally.) This means any sequence of nested pointer cast builtins requires only one result type, rather than one at every intermediate computation.
pointer_cast.zig
:
test "pointer casts" {
const ptr1: *align(1) const u32 = @ptrFromInt(0x1000);
const ptr2: *u64 = @constCast(@alignCast(@ptrCast(ptr1)));
_ = ptr2;
}
$ zig test pointer_cast.zig
1/1 test.pointer casts...
OK All 1 tests passed.
3 Likes