Initializing [*c]const [*c]const u8

I’m trying to use a C function from Zig, and the function has a parameter with a type like this: char const * const * When I imported the header file into Zig it became [c*]const [*c]const u8. Now I want to initialize an array with values (string literals) and pass it to this function. But when I try something like this:

const myArray = [_][*c]const u8 { "foo", "bar" };
myFunction(myArray);

I get a compiler error: expected type '[*c]const [*c]const u8', found '[2][*c]const u8',

If I try this:

const myArray = [_]const [*c]const u8 { "foo", "bar" };

then I get a different compiler error: pointer modifier 'const' not allowed on array child type

No matter what variation I try I still get compiler errors.

I think in general you shouldn’t have variables with raw [*c] types. It’s best to use the more specific Zig pointer types and just let them coerce/cast to and from the raw C types at the point of calling the C API.

If your sub-arrays are null-terminated C style strings then the correct type to construct would be:

// @TypeOf(ptr) = *const [2][*:0]const u8
const ptr = &[_][*:0]const u8{ "foo", "bar" };

// this type can coerce to [*c]const [*c]const u8
const cptr: [*c]const [*c]const u8 = ptr;
5 Likes

Also, you can pass the slice.ptr field to c-style pointers too if you need to get from a slice to a direct pointer. A little different than your example, but still handy.

fn foo(_: [*c]const u8) i32 { // ...

const hello: []const u8 = "hello";

foo(hello.ptr); // will coerce
1 Like

That works, but now I’m trying to wrap my head around why, specifically what the & is for. In my mind this is creating something closer to char*** in C-world, even though the function is asking for something more like char**.

1 Like

In declaration foo: [10]T,
foo is the entire array, &foo is the address of the array (a pointer).
When you call bar(foo) you pass the entire array by value (not always, zig can optimize this call).
When you call bar(&foo) you pass by value the pointer to the array.

1 Like

you pass the entire array by value (not always, zig can optimize this call)

AFIK, nim will optimize that larger than 24bytes to *const. So what are the optimization rules in zig? :thinking:

Zig pass primitive values by value and everything else either by value or by reference at will.
https://ziglang.org/documentation/master/#Pass-by-value-Parameters

1 Like

also there was some not so ancient and somewhat interesting discussion, sorry for replying to closed question

3 Likes

I think your reply is good and falls under:

  • You have additional details

Adding useful related information to solved help topics is good.
We just don’t want discussions to go totally off topic instead of just creating a new topic for it, when it doesn’t really match what was the main discussion.

Thank you sharing the link. I was trying to find the video that discussed the aliasing problem but couldn’t.