我有两个不同的C函数,我想将它们与Python中的ctypes一起使用。
一个函数正在建立连接,并返回指向truct的指针。指针应在第二个函数中用作自变量,以重用已建立的连接。
C代码:
customStruct * connect()
{
customStruct *obj = connection_helper();
return obj;
}
void foo(customStruct * obj)
{
foo_helper(obj);
}
Python代码:
from ctypes import *
lib = CDLL("./test.dll")
obj = lib.connect()
lib.foo(obj)
[不幸的是,我致电lib.foo()
时检索到访问冲突错误。我可以使用具有customStruct
属性的类在Python中重新创建_fields_
结构,但是由于该结构包含许多其他结构,并且由于我不想访问Python本身中的结构成员,因此我在考虑另一种方法是如何创建可重复使用的标识符。
我可以根据需要更改connect()
和foo()
的定义。如果可以让我不必在python中重新创建该结构,我还可以创建另一个“标识符”结构。
更新:看来我必须使用函数byref()
才能实现所需的功能。https://docs.python.org/3/library/ctypes.html#ctypes.byref
文档指出“返回的对象只能用作外部函数调用参数”,但我不确定然后在connect()
中返回什么。
就像在评论中已经提到的那样,您需要在Python端为connect函数设置restype并为foo函数设置argtypes。
在代码中看起来像这样:
from ctypes import *
lib = cdll.LoadLibrary("some.dll")
lib.connect.restype = c_void_p
lib.foo.argtypes = c_void_p,
obj = lib.connect()
lib.foo(obj)
Test
简短测试应验证这在C端的连接和foo函数中是否提供相同的指针。
您的代码经过稍微修改的版本可能看起来像这样:
#include <stdlib.h>
#include <stdio.h>
typedef struct {
int x;
} customStruct;
static customStruct *connection_helper() {
return malloc(sizeof(customStruct));
}
customStruct *connect()
{
customStruct *obj = connection_helper();
printf("connect: %p\n", obj);
return obj;
}
void foo(customStruct * obj)
{
printf("foo: %p\n", obj);
//do something
}
如果运行此命令,则会得到类似的内容:
connect: 0x7fa219e094a0
foo: 0x7fa219e094a0
[如果您具有不透明的结构(您不知道其成员,或者不希望了解其成员),则仍应创建一个类以在python中表示该结构。然后,您可以使用此类来正确键入您的函数。这将有助于防止错误地将错误对象作为“ CustomStruct”指针传递给错误对象。
例如:
from ctypes import cdll, c_int, c_void_p
mylib = cdll.LoadLibrary('mylib')
class CustomStructP(c_void_p):
# subclassing c_void_p creates an opaque pointer type that is distinct
# from c_void_p, and can only be instantiated as a pointer
pass
create = mylib.create
create.argtypes = [c_int]
create.restype = CustomStructP
display = mylib.display
display.argtypes = [CustomStructP]
display.restype = None
delete = mylib.delete
delete.argtypes = [CustomStructP]
delete.restype = None
obj = create(10)
display(obj)
delete(obj)
display(CustomStructP()) # passing a null pointer
现在,如果您尝试类似的操作:display(c_void_p())
,您将得到:
Traceback (most recent call last):
File "C:\Users\User\Documents\python\src\main.py", line 31, in <module>
display(c_void_p())
ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type
我使用的C代码是:
#include <stdio.h>
#include <stdlib.h>
struct customStruct {
int val;
};
struct customStruct *
create(int val) {
struct customStruct *obj = malloc(sizeof(struct customStruct));
obj->val = val;
return obj;
}
void
display(struct customStruct *obj) {
if (obj) {
printf("customStruct(%d) @ %p\n", obj->val, obj);
}
else {
puts("customStruct is NULL");
}
}
void
delete(struct customStruct *obj) {
free(obj);
}