SWIG 'cstring.i' Python 返回字节类型而不是字符串类型
Posted
技术标签:
【中文标题】SWIG \'cstring.i\' Python 返回字节类型而不是字符串类型【英文标题】:SWIG 'cstring.i' Python return byte type instead of string typeSWIG 'cstring.i' Python 返回字节类型而不是字符串类型 【发布时间】:2016-08-10 18:24:25 【问题描述】:我有一个类似的 C 函数
int foo(void ** buf, int * buf_size)
我使用cstring.i
包装它以在 Python 3 中使用。包装的 Python 函数的结果是字符串类型。
有没有办法得到二进制类型的结果?
背景:buf
填充的数据是 msgpack 编码数据,因此在 Python 中使用 str.decode
不是一种选择。 Python 的 msgpack 实现只接受二进制数据。
【问题讨论】:
使用来自cstring.i
的cstring_chunk_output
。这可用于返回一大块二进制输出。同样cstring_chunk_output
是另一种方式
使用cstring_chunk_output
也会导致函数返回str
,而不是bin
。此外,在我的情况下,数据的大小是未知的(因此int * buf_size
。根据 cstring.i 文档,cstring_output_allocate_size
是可行的方法(并且有效),唯一的问题是,如上所述, Python 中的返回输入为str
。
在 Python 中将二进制内容作为字符串是完全有效的。特殊字符被转义。在 NumPy 数组上调用 tostring 可以将二进制输出作为字符串
是的,但是msgpack-python
库需要类似字节的数据并拒绝str
。用于转换为例如bytearray
,你需要提供一个编码,它要么失败要么弄乱数据。我还没有找到任何方法来按原样转换str
。
我明白了。从 SWIG 代理对象获取 char* 应该非常简单。我稍后提供答案
【参考方案1】:
如果你使用%cstring_output_allocate_size
,包装函数_wrap_foo
会调用SWIG_FromCharPtrAndSize()
,其解码逻辑如下:
#if PY_VERSION_HEX >= 0x03000000
#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR)
return PyBytes_FromStringAndSize(carray, (Py_ssize_t)(size));
#else
#if PY_VERSION_HEX >= 0x03010000
return PyUnicode_DecodeUTF8(carray, (Py_ssize_t)(size), "surrogateescape");
#else
return PyUnicode_FromStringAndSize(carray, (Py_ssize_t)(size));
#endif
#endif
#else
return PyString_FromStringAndSize(carray, (Py_ssize_t)(size));
#endif
因此,您可以通过#defining SWIG_PYTHON_STRICT_BYTE_CHAR
获取字节而不是 unicode 字符串。这在http://www.swig.org/Doc3.0/Python.html 中有记录,因此它是一个官方功能。但由于它是一个全局开关,因此只有在您希望所有字符串参数都映射到字节时才有用。如果您需要在 API 中混合使用 str
和 bytes
,我能看到的唯一解决方案是自定义类型映射。
【讨论】:
请注意,这是一项新功能。它在 swig 3.0.8 中不可用,但在 swig 3.0.10 中可用。 自从我切换到 ctypes 后,我还没有尝试过这个解决方案(对于我的情况来说完全足够了),但我想这是要走的路。 (迟到)感谢您的回答!【参考方案2】:在https://github.com/bit-01101/ctypesgen 的帮助下,我使用ctypes
解决了我的问题
【讨论】:
以上是关于SWIG 'cstring.i' Python 返回字节类型而不是字符串类型的主要内容,如果未能解决你的问题,请参考以下文章
Swig/python:啥时候需要 SWIG_init()?