create_string_buffer抛出错误TypeError:str / bytes而不是str实例

时间:2011-08-29 23:25:27

标签: python string pointers ctypes

我正在尝试这个简单的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

有谁知道我做错了什么?

在同一个注释中,我试图从我的python代码将指向字符串的指针传递给C函数,以便我可以在那里执行一些字符串操作并返回另一个字符串。有人可以给我一些关于如何做的示例代码吗?

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

3 个答案:

答案 0 :(得分:11)

您使用的是Python 3,Python 3中的字符串(str - type)是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>

关于问题的第2部分,是否要编辑现有字符串或返回在堆上分配的全新字符串?如果是前者,使用create_string_buffer将可变字符串传递给函数并在适当的位置修改它将起作用。这是一个从Windows MSVCRT库调用_strupr()的简单示例:

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字节字符串传递给带const char*的C函数,因为直接通过ctypes修改Python字符串是 Bad TM

答案 1 :(得分:8)

关于使它工作,如果你传递一个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_charcreate_string_buffer相关的错误位于同一个字段中,但没有报告给它str现在失败了(但是有明确的例子表明它曾经工作过在Py3K)。

答案 2 :(得分:0)

参数是字符串所需缓冲区的大小,因此将缓冲区的长度传递给它。它将创建一个大小相同的char数组。

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