Zig中实例化含非公共类型的PyObject结构体报错如何解决?
在Zig中实例化PyObject的未公开Union问题解决方法
问题背景
我尝试在Zig 0.13.0中实例化PyObject,该类型在C中的本质定义如下:
struct _object { union { Py_ssize_t ob_refcnt; PY_UINT32_T ob_refcnt_split[2]; }; PyTypeObject *ob_type; }; typedef struct _object PyObject;
Zig通过@cImport导入后,生成的对应代码为:
const union_unnamed_11 = extern union { ob_refcnt: Py_ssize_t, ob_refcnt_split: [2]u32, }; pub const struct__object = extern struct { unnamed_0: union_unnamed_11 = @import("std").mem.zeroes(union_unnamed_11), ob_type: [*c]PyTypeObject = @import("std").mem.zeroes([*c]PyTypeObject), }; pub const PyObject = struct__object;
我最初尝试用以下代码实例化PyObject:
const py = @cImport({ @cInclude("Python.h"); }); var pyObject = py.PyObject{ .unnamed_0 = py.union_unnamed_11{ .ob_refcnt = 1 }, .ob_type = null, }; // main 函数及其他代码..
但编译时出现错误:
$ zig build-exe t.zig -I /usr/include/python3.13 -I /usr/include -I /usr/include/x86_64-linux-gnu t.zig:8:20: error: 'union_unnamed_11' is not marked 'pub' .unnamed_0 = py.union_unnamed_11{ .ob_refcnt = 1 },
由于无法修改生成的union_unnamed_11类型的可见性,需要通过其他方式解决这个问题。
解决方案
方法1:利用Zig复合字面量自动推导类型
直接通过匿名union语法初始化unnamed_0字段,Zig会自动推导其类型为对应的未公开union:
const py = @cImport({ @cInclude("Python.h"); }); var pyObject = py.PyObject{ .unnamed_0 = .{ .ob_refcnt = 1 }, .ob_type = null, };
方法2:通过@TypeOf获取union类型
先通过PyObject结构体的字段获取对应的union类型,再用该类型初始化:
const py = @cImport({ @cInclude("Python.h"); }); const PyObjectUnion = @TypeOf(py.PyObject.unnamed_0); var pyObject = py.PyObject{ .unnamed_0 = PyObjectUnion{ .ob_refcnt = 1 }, .ob_type = null, };
原理说明
Zig在导入C代码时,会将未命名的C union转换为未标记pub的Zig union类型,因此无法直接通过模块路径访问。但我们可以通过结构体字段的类型推导或者复合字面量的自动类型匹配来绕过这个限制,无需直接引用未公开的union_unnamed_11类型名称。
内容的提问来源于stack exchange,提问作者Matías Santurio
相关产品推荐
相关产品推荐

