Строка Python на C++ на строку Python

Я борюсь с преобразованием из 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', что явно означает, что что-то пошло не так.

Кто-нибудь может определить проблему?

Почему c_wchar_p для char?

Matthieu Brucher 29.10.2018 17:11

Закодированы ли ваши байтовые строки в Юникоде?

GWW 29.10.2018 17:12

@MatthieuBrucher, насколько я понимаю, c_wchar_p соответствует представлению Unicode, которое является str в Python 3 ('abc') и таким же, как unicode в Python 2

Dimebag 29.10.2018 17:21

Если вы используете str и bytes, разве это не должно быть char, как в юникоде?

Matthieu Brucher 29.10.2018 17:22

Переход на c_char_p не имеет никакого эффекта

Dimebag 29.10.2018 17:34
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
5
162
2

Ответы 2

Возможно, вы ожидаете, что 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 не имеет никакого эффекта (?). Еще работает.

Другие вопросы по теме