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.icstring_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 中混合使用 strbytes,我能看到的唯一解决方案是自定义类型映射。

【讨论】:

请注意,这是一项新功能。它在 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()?

Python 属性和 Swig

Python:SWIG 与 ctypes

SWIG:你能否使用 SWIG 专门使用 C++ 头文件使 C++ 在 Python 中可用?

没有 DLL 的 SWIG + Python

使用 SWIG 为 python2 和 python3 创建一个模块