从Python str到C ++到Python str

时间:2018-10-29 16:04:35

标签: python c++

我正在努力从Python str转换为C ++,然后再转换回来。为了与Python 2/3兼容,我认为分别为Py2 / 3使用str / bytes就足够了(定义)。

请注意,这是从较大的代码库中提取的;对于任何丢失的进口商品表示歉意。

// C++ stuff compiled to convertor.so
#include "Python.h"
#if PY_MAJOR_VERSION >= 3
    #define PyString_Size PyBytes_Size
    #define PyString_AsString PyBytes_AsString
    #define PyString_FromStringAndSize PyBytes_FromStringAndSize
#endif

template<typename T>
struct vec {
  T *ptr;
  i64 size;
};

extern "C"
vec<uint8_t> str_to_char_arr(PyObject* in) {
  int64_t dimension = (int64_t) PyString_Size(in);
  vec<uint8_t> t;
  t.size = dimension;
  t.ptr = (uint8_t*) PyString_AsString(in);
  return t;
}

extern "C"
PyObject* char_arr_to_str(vec<uint8_t> inp) {
  Py_Initialize();
  PyObject* buffer = PyString_FromStringAndSize((const char*) inp.ptr, inp.size);
  return buffer;
}


# Python stuff
class Vec(Structure):
    _fields_ = [
        ("ptr", POINTER(c_wchar_p)),
        ("size", c_long),
    ]

lib = to_shared_lib('convertor')
lib_file = pkg_resources.resource_filename(__name__, lib)
utils = ctypes.PyDLL(lib_file)

str_to_char_arr = utils.str_to_char_arr
str_to_char_arr.restype = Vec()
str_to_char_arr.argtypes = [py_object]

encoded = str_to_char_arr('abc'.encode('utf-8'))

char_arr_to_str = utils.char_arr_to_str
char_arr_to_str.restype = py_object
char_arr_to_str.argtypes = [py_object.ctype_class]
result = ctypes.cast(encoded, ctypes.POINTER(Vec())).contents

decoded = char_arr_to_str(result).decode('utf-8')

在python 3.5上使用'abc'进行尝试似乎会产生'\x03\x00\x00',这显然意味着出了点问题。

有人可以发现问题吗?

2 个答案:

答案 0 :(得分:0)

可能是您希望使用UCS2,并且为UCS4配置了Python。另请参见Building an UCS4 string buffer in python 2.7 ctypes

答案 1 :(得分:0)

尚未设法使此功能适用于Python 2;也许有人更了解Python版本之间的unicode / str / bytes差异来解决此问题。同样,这意味着我遇到的问题可能与另一个软件包有关,不幸的是我无法控制atm。

不过,这是一些适用于Python 3.5和clang 6.0的工作代码(对我来说)。

#include "Python.h"

#if PY_MAJOR_VERSION >= 3
    #define PyString_Size PyBytes_Size
    #define PyString_AsString PyBytes_AsString
    #define PyString_FromStringAndSize PyBytes_FromStringAndSize
#endif

template<typename T>
struct vec {
  T *ptr;
  int64_t size;
};

extern "C"
vec<uint8_t> str_to_char_arr(PyObject* in) {
  int64_t dimension = (int64_t) PyString_Size(in);
  vec<uint8_t> t;
  t.size = dimension;
  t.ptr = (uint8_t*) PyString_AsString(in);
  return t;
}

extern "C"
PyObject* char_arr_to_str(vec<uint8_t> inp) {
  Py_Initialize();
  PyObject* buffer = PyString_FromStringAndSize((const char*) inp.ptr, inp.size);
  return buffer;
}


# Python
from ctypes import *

import pkg_resources


class Vec(Structure):
    _fields_ = [
        ("ptr", POINTER(c_char_p)),
        ("size", c_long),
    ]


lib = 'test.so'
lib_file = pkg_resources.resource_filename(__name__, lib)
utils = PyDLL(lib_file)

str_to_char_arr = utils.str_to_char_arr
str_to_char_arr.restype = Vec
str_to_char_arr.argtypes = [py_object]

encoded = str_to_char_arr('Bürgermeister'.encode('utf-8'))

char_arr_to_str = utils.char_arr_to_str
char_arr_to_str.restype = py_object
char_arr_to_str.argtypes = [Vec]

decoded = char_arr_to_str(encoded).decode('utf-8')
print(decoded)  # Bürgermeister

c_char_p更改为c_wchar_p似乎没有效果(?)。仍然有效。