在Python扩展对象中使用宽字符成员可行吗?

2 投票
1 回答
1658 浏览
提问于 2025-04-16 18:42

在Python的C扩展中,创建一个对象的成员变量,类型是char *,其实很简单。你只需要在PyMemberDef声明中使用T_STRING这个定义就可以了。

但是,为什么似乎没有和wchar_t *相对应的东西呢?如果真的有,那是什么呢?

举个例子:

struct object里有一个char *text

PyMemberDef数组里有{"text", T_STRING, offsetof(struct object, text), READONLY, "这是一段普通的字符字符串。"}

而如果是类似这样的:

struct object里有一个wchar_t *wtext

PyMemberDef数组里就应该有{"wtext", T_WSTRING, offsetof(struct object, wtext), READONLY, "这是一段宽字符字符串"}

我明白像PyUnicode_AsString()这样的函数可以用来把数据编码成UTF-8,存储在普通的字符字符串里,然后再解码。但这样做就需要对通用的getattrsetattr方法进行封装,以处理编码后的文本。而且当你想在结构体中使用固定大小的字符数组时,这种方法就不太方便了,因为你不希望能存储的字符数量发生变化。

1 个回答

2

直接使用 wchar_t 这个类型并不适合在不同的平台上使用,因为它的表现可能会有所不同。Python 为了处理 Unicode 字符,定义了一个叫 Py_UNICODE 类型,作为存储 Unicode 字符的单位。

根据你使用的平台,Py_UNICODE 可能会被定义为 wchar_t(如果这个类型可用的话),或者是一个无符号短整型、整型或长整型。它的大小会根据 Python 的配置(比如 UCS2 或 UCS4)以及使用的架构和 C 编译器而有所不同。你可以在 unicodeobject.h 文件中找到相关的定义。

在你的使用场景中,你的对象可以有一个属性是 Unicode 字符串,使用 T_OBJECT 来表示:

static struct PyMemberDef attr_members[] = {
  { "wtext", T_OBJECT, offsetof(PyAttrObject, wtext), READONLY, "wide string"}
  ...

你可以在对象的初始化函数中进行类型检查:

...
if (!PyUnicode_CheckExact(arg)) {
    PyErr_Format(PyExc_ValueError, "arg must be a unicode string");
    return NULL;
}
Py_INCREF(arg);
self->wtext = arg;
...

如果你需要遍历 Unicode 字符串中的低级字符,可以使用一个宏,它会返回一个 Py_UNICODE * 指针:

int i = 0;
Py_ssize_t size = PyUnicode_GetSize(self->wtext);
Py_UNICODE *chars = PyUnicode_AS_UNICODE(self->wtext);
for (i = 0; i < size; i++) {
    // use chars[i]
    ...

撰写回答