ctypes 改变结构值

阿维沙阿

这是我的 C 代码:

typedef struct {
    int a;
}A;

__declspec(dllexport) A new_a(int x) {
    A a = {x};
    return a;
}

__declspec(dllexport) void change(A a) { a.a++; }

__declspec(dllexport) int get_a (A a) { return a.a; }

我将它编译成一个 MODULE DLL,在 Python 中我这样做了:

import ctypes

lib = ctypes.windll.LoadLibrary('C:\\Users\\avishah\\CLionProjects\\Math\\lib\\libpythonclass2.dll')

a = lib.new_a(10)
print(lib.get_a(a), type(a))  # gives 10, says type of a is 'int'
lib.change(a)  # doesn't change value
print(lib.get_a(a))  # still shows 10

我确定我必须在 C 代码中使用指针,但它通常给我这个错误:

OSError: exception: access violation reading 0x000000000000000A
用户3840170

您的代码有两个问题。

第一个是您没有为您导入的 FFI 函数指定类型签名。您需要为您的结构创建类型定义,并将参数和返回类型分配给导入的函数。

import ctypes

lib = ctypes.windll.LoadLibrary(r'C:\Users\avishah\CLionProjects\Math\lib\libpythonclass2.dll')

class A(ctypes.Structure):
    _fields_ = (
        ('a', ctypes.c_int),
    )

new_a = lib.new_a
new_a.restype = A
new_a.argtypes = (ctypes.c_int,)

change = lib.change
change.restype = None
change.argtypes = (A,)

get_a = lib.get_a
get_a.restype = ctypes.c_int
get_a.argtypes = (A,)

二是change函数按值接收结构体。换句话说,该函数对参数列表上接收到的结构的副本进行操作,这意味着调用者持有的副本永远不会被修改。要实际修改结构,您需要传递一个指针:

__declspec(dllexport) void change(A *a) { a->a++; }
change = lib.change
change.restype = None
change.argtypes = (ctypes.POINTER(A),)

现在您的代码应该如您所愿:

a = new_a(10)
print(get_a(a), type(a))   # should print 10 <class '__main__.A'>
change(ctypes.byref(a))    # equivalent C: change(&a);
print(get_a(a))            # should print 11

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章