Я борюсь с преобразованием из Python str в C++ и обратно. Для совместимости с Python 2/3 я подумал, что будет достаточно использовать str / bytes для Py2 / 3 соответственно (определения).
Обратите внимание, что это извлечено из более крупной кодовой базы; приносим свои извинения за отсутствующий импорт.
// 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')
Попытка этого с 'abc' на python 3.5, похоже, дает '\x03\x00\x00', что явно означает, что что-то пошло не так.
Кто-нибудь может определить проблему?
Закодированы ли ваши байтовые строки в Юникоде?
@MatthieuBrucher, насколько я понимаю, c_wchar_p соответствует представлению Unicode, которое является str в Python 3 ('abc') и таким же, как unicode в Python 2
Если вы используете str и bytes, разве это не должно быть char, как в юникоде?
Переход на c_char_p не имеет никакого эффекта






Возможно, вы ожидаете, что UCS2, а Python настроен для UCS4. См. Также Создание строкового буфера UCS4 в Python 2.7 ctypes
Не удалось выполнить эту работу для Python 2; возможно, кто-то лучше понимает различия unicode / str / bytes между версиями Python, чтобы исправить это. Также это означает, что проблема, вероятно, связана с другим пакетом, который, к сожалению, не контролируется банкоматом.
Тем не менее, вот некоторый рабочий код (для меня) с 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 не имеет никакого эффекта (?). Еще работает.
Почему c_wchar_p для char?