How to access the return value of a C function that can return null to return an error?

First you need to get your type correct, note 0 and null are different values.
I think in your case, your type is basically this, but without the optional:

So we end up with:

const result: [*:null][*:0]const u8 = @ptrCast(clib.string_split(allocator, str.ptr, delim.ptr));

A null result is equal to a null-sentinel-terminated slice of length zero, so optional would make us handle the same thing in two different ways.

Now we can convert the outer sentinel-terminated slice to a normal slice:

const results = std.mem.span(result);
if(results.len > 0) {
  return results;
} else {
  return CResult.Null;
}

Also your input types should be zero terminated, so you end up with:

pub fn stringSplit(allocator: *Callocator, str: [:0]const u8, delim: [:0]const u8) ![][:0]const u8 {
    const result: [*:null][*:0]const u8 = @ptrCast(clib.string_split(allocator, str.ptr, delim.ptr));
    const results = std.mem.span(result);
    if(results.len > 0) {
        return results;
    } else {
        return CResult.Null;
    }
}

Personally I would stop here, because I find this is an easy middle ground where the types basically meet in the middle. I don’t think there is a big reason to go all the way to eliminate the inner sentinel terminated slices, instead I would just work with the inner sentinel terminated slices directly.

If you want to convert to all non-sentinel slices anyway you can use one of the approaches @dimdin pointed out.

1 Like