Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 3.x PythonCallable上奇怪的ctypes行为用c_char_p argtype包装c callable_Python 3.x_String_Byte_Ctypes_Mutable - Fatal编程技术网

Python 3.x PythonCallable上奇怪的ctypes行为用c_char_p argtype包装c callable

Python 3.x PythonCallable上奇怪的ctypes行为用c_char_p argtype包装c callable,python-3.x,string,byte,ctypes,mutable,Python 3.x,String,Byte,Ctypes,Mutable,在以下测试程序中,我观察到一种奇怪的ctypes相关行为: import ctypes as ct def _pyfunc(a_c_string): print(type(a_c_string)) a_c_string.value = b"87654321" return -123 my_str_buf = ct.create_string_buffer(b"test1234") print(type(my_str_buf))

在以下测试程序中,我观察到一种奇怪的ctypes相关行为:

import ctypes as ct

def _pyfunc(a_c_string):
    print(type(a_c_string))
    a_c_string.value = b"87654321"
    return -123

my_str_buf = ct.create_string_buffer(b"test1234")
print(type(my_str_buf))

my_str_buf[3] = b'*'
print(my_str_buf.value)

my_str_buf.value = b"4321test"
print(my_str_buf.value)

signature = ct.CFUNCTYPE(ct.c_int, ct.c_char_p)
pyfunc = signature(_pyfunc)
pyfunc(my_str_buf)
print(my_str_buf.value)
该示例通过cTypesAPI将可调用的python c封装在python函数中。 目标是向python函数传递一个指向c字符串的指针,让它修改它的内容(提供一个假值),然后返回给调用方

我首先通过ctypes函数创建一个可变字符串缓冲区
create\u string\u buffer
。 从示例中可以看出,字符串缓冲区确实是可变的

之后,我使用
ctypes.CFUNCTYPE(ct.c_int,ct.c_char_p)
创建了一个c函数原型,然后用我的python函数实例化该原型,该函数应该使用相同的签名调用。最后,我使用可变字符串缓冲区调用python函数

令我恼火的是,调用函数时,传递给该函数形状的参数从
类型变为
。不幸的是,原来的可变数据类型变成了一个完全无用的非可变字节对象

这是ctypes错误吗?Python版本是3.6.6

以下是输出:

<class 'ctypes.c_char_Array_9'>
b'tes*1234'
b'4321test'
<class 'bytes'>
Traceback (most recent call last):
  File "_ctypes/callbacks.c", line 234, in 'calling callback function'
  File "C:/Users/andree/source/Python_Tests/ctypes_cchar_prototype.py", line 5, in _pyfunc
    a_c_string.value = b"87654321"
AttributeError: 'bytes' object has no attribute 'value'
b'4321test'

b'tes*1234'
b'4321测试'
回溯(最近一次呼叫最后一次):
文件“\u ctypes/callbacks.c”,第234行,“调用回调函数”
文件“C:/Users/andree/source/Python_Tests/ctypes_cchar_prototype.py”,第5行,在_pyfunc中
a_c_string.value=b“87654321”
AttributeError:“字节”对象没有属性“值”
b'4321测试'
预期产出:

<class 'ctypes.c_char_Array_9'>
b'tes*1234'
b'4321test'
<class 'ctypes.c_char_Array_9'>
b'87654321'

b'tes*1234'
b'4321测试'
b'87654321'

ctypes.c\u char\u p
自动转换为Python
字节。如果不希望出现这种行为,请使用以下任一选项:

  • ctypes.POINTER(ctypes.c_char))
  • 类PCHAR(ctypes.c\u char\p):传递
    (派生抑制该行为)
请注意,
LP_c_char
没有
.value
属性,因此我必须直接取消引用指针以影响值的更改

另外,注意不要超过传入的可变缓冲区的长度。我添加了
length
作为附加参数

例如:

将ctypes导入为ct
@CFUNCTYPE(ct.c_int,ct.POINTER(ct.c_char),ct.c_size\t)
def pyfunc(a_c_字符串,长度):
new_data=b'87654321\x00'#确保存在新的空终止。
如果len(新数据)>长度:#确保新数据不超过缓冲区长度
返回0#失败
对于枚举中的i,c(新的_数据):
a_c_字符串[i]=c
返回1#通过
my_str_buf=ct.创建字符串缓冲区(10)
结果=pyfunc(my_str_buf,len(my_str_buf))
打印(结果,我的字符串值)
my_str_buf=ct.创建字符串缓冲区(8)
结果=pyfunc(my_str_buf,len(my_str_buf))
打印(结果,我的字符串值)
1b'87654321'
0 b“

如果将参数类型更改为
ct.c_char*9
?所以
signature=ct.CFUNCTYPE(ct.c_int,ct.c_char*9)
。我注意到它仍然不能反映您想要的确切行为。它通过值传递
my_str_buf
。如果您想在函数中变异
my_str_buf
,可以通过引用传递它,比如
pyfunc(ct.byref(my_str_buf))
。这将要求您将参数类型更改为指向字符数组的指针
signature=ct.CFUNCTYPE(ct.c_int,ct.POINTER(ct.c_char*9))
并在函数中修改该指针的内容
a_c_string.contents.value=b“87654321”
总之,这应该会给你想要的行为。这也很有效。作为一个副作用,它需要我传递精确宽度的字符串。这可能是一个优势,也可能不是。对我来说,这很好,这对我很有帮助。奇怪的是,如果我使用
ct.CFUNCTYPE(ct.c_int,ct.POINTER(ct.c_char),ct.c_size_t)
ct.CFUNCTYPE(ct.c_int,ct.c_char_p,ct.c_size_t)
。思想
ct.c\u char\u p
仅仅是
ct.POINTER(ct.c\u char)
@pqans
c\u char\u p
的别名,对转换为Python字节对象有特殊处理。这不仅仅是一个别名,这也是我误解的根源。很高兴知道。@pqnas
c\u void\u p
具有类似的特殊处理。它转换为Python
None
或Python
int
“请注意,LP_c_char没有.value属性,因此我必须直接[…]”->需要使用
.contents.value