我有一个与 c 库 (xlib) 集成的 Zig 项目。该库有一个方法,要求我将整个 argv 数组作为参数传递给它。在 zig extern 定义中,库函数的 argv 参数的预期类型是
[*c][*c]u8
。
当我运行 Linux 时,我使用非跨平台方式在 zig 中获取 cli 参数
var argv = std.os.argv;
之字形参数的类型为
[][*:0]u8
。我有 2 个问题。
[][*:0]u8
-> [*c][*c]u8
)[*c][*c]u8
到底是什么意思?我已经很久没有在这么低的水平上工作了。我是否正确理解
[*c][*c]u8
是一个 c 指针列表,其中每个 c 指针都是指向以 null 结尾的字符串的第一个字符的指针?
切片上的将 Zig vargs 转换/构建为 C vargs 的最实用方法是什么([][*:0]u8 -> [*c][*c]u8)
@ptrCast
.ptr
属性:
const argv = std.os.argv;
const c_ptr: [*c][*c]u8 = @ptrCast(argv.ptr);
(我认为这里不需要指针强制转换 - 它应该能够隐式强制转换
argv.ptr
,但它拒绝隐式强制转换指针子项)
[*c][*c]u8 到底是什么意思?
之字形指针有点令人困惑。有具有不同选项和相似语法的指针、切片和值数组:
*u8
:指向 u8 值的指针。可以取消引用 (value.*
) 但不能索引 (value[0]
)[*]u8
:指向 u8 值的未知长度的多项指针。可以建立索引,但不能取消引用。[*c]u8
:一种单项或多项指针类型,仅用于 c 兼容性。它既可以被取消引用,也可以被索引。
int myvalue = 0;
int* mypointer = &myvalue;
*mypointer = 1; // allowed
mypointer[0] = 2; // allowed
[*c]
指针的原因,这两种用途都允许。[]u8
:一个切片,它是一个指针和一个长度。它类似于struct {ptr: [*]u8, len: usize}
。它可以被索引但不能取消引用。[N]u8
:值数组类型。这不是一个指针,尽管它看起来像一个。未知长度的指针和切片可以有标记值。
[:0]u8
指定切片在最后一项 (0
) 之后有一个 slice[slice.len] == 0
。 [*:0]u8
指定虽然长度未知,但数组最后一项之后的项应该是 0
。
常规指针和未知长度指针都可以隐式转换为 C 兼容性指针。
现在回答问题
[*c]
一个或多个项目指针包含
[*c]
一个或多个项目指针包含
因为我们知道它们是数组,所以 zig 中更好的表示是
[*][*:0]u8
,数组的数组。 translate-c
不知道这一点,所以它发出 C 兼容性指针。
[*]
未知长度数组指针,包含
[*:0]
长度未知 0
-哨兵数组指针包含
因为我们也知道外部数组的长度(带有argv),所以我们可以将指针
[*][*:0]u8
和长度usize
组合成一个切片:[][*:0]u8
。
这就是为什么
std.os.argv
返回 [][*:0]u8
。