create_string_buffer 报错 TypeError: 期望 str/bytes 类型但得到 str 实例
我正在尝试这个简单的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 个回答
这个参数是你需要的字符串缓冲区的大小,所以你要把缓冲区应该有多长传给它。这样它就会创建一个那个大小的字符数组。
>>> from ctypes import create_string_buffer
>>> buf = create_string_buffer(20)
>>> buf
<ctypes.c_char_Array_20 object at 0x355348>
>>>
你正在使用Python 3,在Python 3中,字符串(str
类型)是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
来传递一个可变的字符串给函数,这样在原地修改就可以了。下面是一个简单的例子,调用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字符串是不好的TM。
关于让它正常工作,如果你传入一个 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
这显示了相同的行为。看起来你发现了一个bug。
是时候去看看 http://bugs.python.org 了。这里有一些和 c_char
以及 create_string_buffer
相关的bug,它们在同一个领域,但没有报告说现在传入 str
会失败(不过确实有例子显示在Py3K中以前是可以的)。