我正在尝试这个简单的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;
}
答案 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_char
和create_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>
>>>