Ошибка создания create_string_buffer TypeError: ожидается str / bytes вместо экземпляра str - PullRequest
13 голосов
/ 30 августа 2011

Я пробую этот простой пример ctypes и получаю упомянутую ошибку

>>> from ctypes import create_string_buffer
>>> str = create_string_buffer("hello")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python32\lib\ctypes\__init__.py", line 59, in create_string_buffer
buf.value = init
TypeError: str/bytes expected instead of str instance

Кто-нибудь знает, что я делаю не так?

В той же заметке я пытаюсь передать указатель на строку в функцию C из моего кода на python, чтобы я мог выполнить некоторую строковую операцию там и вернуть другую строку. Может кто-нибудь дать мне пример кода, как это сделать?

extern "C" __declspec(dllexport) char * echo(char* c)
{
      // do stuff
    return c;
}

Ответы [ 3 ]

11 голосов
/ 30 августа 2011

Вы используете Python 3, а строки (str -типа) в Python 3 являются объектами Unicode. create_string_buffer создает массивы C char, поэтому вам необходимо передать объект bytes. Если у вас есть объект str, закодируйте его с помощью соответствующей кодировки, чтобы создать объект bytes. Обратите внимание, что create_unicode_buffer также создает массивы C wchar и принимает объекты Python 3 str.

Python 3.2.1 (default, Jul 10 2011, 21:51:15) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes
>>> ctypes.create_unicode_buffer('abcd')
<ctypes.c_wchar_Array_5 object at 0x00C2D300>
>>> ctypes.create_string_buffer(b'abcd')
<ctypes.c_char_Array_5 object at 0x00C2D1C0>
>>> ctypes.create_string_buffer('abcd'.encode('utf-8'))
<ctypes.c_char_Array_5 object at 0x00C2D300>

Что касается второй части вашего вопроса, хотите ли вы отредактировать существующую строку или вернуть полностью новую строку, выделенную в куче? Если первое, использование create_string_buffer для передачи изменяемой строки в функцию и ее изменения на месте будет работать. Вот простой пример вызова _strupr () из библиотеки Windows MSVCRT:

Python 3.2.1 (default, Jul 10 2011, 21:51:15) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes
>>> c = ctypes.CDLL('msvcr90.dll')
>>> strupr = c._strupr
>>> a=ctypes.create_string_buffer(b'abc')
>>> strupr.restype=ctypes.c_char_p
>>> strupr(a)
b'ABC'

Обратите внимание, что установка restype (тип результата) функции на c_char_p указывает ctypes преобразовывать возвращаемое значение в объект bytes. Также обратите внимание, что _strupr преобразует строку на месте, поэтому должен быть передан изменяемый строковый буфер. Передавать только байтовые строки Python в функции C, которые принимают const char*, поскольку изменение строк Python напрямую через ctypes Bad TM .

8 голосов
/ 30 августа 2011

Что касается того, чтобы заставить его работать, если вы передаете ему объект bytes, он работает:

>>> import ctypes
>>> ctypes.create_string_buffer(b'hello')
<ctypes.c_char_Array_6 object at 0x25258c0>

Глядя на код для create_string_buffer:

def create_string_buffer(init, size=None):
    """create_string_buffer(aBytes) -> character array
    create_string_buffer(anInteger) -> character array
    create_string_buffer(aString, anInteger) -> character array
    """
    if isinstance(init, (str, bytes)):
        if size is None:
            size = len(init)+1
        buftype = c_char * size
        buf = buftype()
        buf.value = init
        return buf
    elif isinstance(init, int):
        buftype = c_char * init
        buf = buftype()
        return buf
    raise TypeError(init)

Делая это напрямую,

>>> (ctypes.c_char * 10)().value = b'123456789'

Это прекрасно работает.

>>> (ctypes.c_char * 10)().value = '123456789'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: str/bytes expected instead of str instance

Это показывает то же поведение.Мне кажется, что вы нашли ошибку.

Время посетить http://bugs.python.org. Есть несколько ошибок, связанных с c_char и create_string_buffer, которые находятся в одном поле, но ни одногосообщить, что дать ему str теперь не удается (но есть определенные примеры, показывающие, что он работал в Py3K).

0 голосов
/ 30 августа 2011

Аргумент - это размер буфера, требуемого для строки, поэтому передайте ему длину буфера. Это создаст массив символов такого размера.

>>> from ctypes import create_string_buffer
>>> buf = create_string_buffer(20)
>>> buf
<ctypes.c_char_Array_20 object at 0x355348>
>>> 
...