Python ctypes指向结构的指针,作为没有成员访问权限的标识符

问题描述 投票:1回答:2

我有两个不同的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 c struct ctypes
2个回答
1
投票

就像在评论中已经提到的那样,您需要在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

0
投票

[如果您具有不透明的结构(您不知道其成员,或者不希望了解其成员),则仍应创建一个类以在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);
}
© www.soinside.com 2019 - 2024. All rights reserved.