没有为指向结构的指针调用 ctypes.Structure 子类的 ctypes __del__
Posted
技术标签:
【中文标题】没有为指向结构的指针调用 ctypes.Structure 子类的 ctypes __del__【英文标题】:ctypes __del__ of ctypes.Structure subclass not invoked for pointers to structures 【发布时间】:2020-01-26 19:55:13 【问题描述】:我包装的 C 库需要分配和销毁 C 函数内部结构的内存,并且总是传递指针,而不是结构。
我有一个带有__del__
方法的ctypes.Structure
子类。在实例上调用 del
时不会调用此方法,该实例是指向从 C 中的函数返回的结构的指针 (Foo_init
)。有趣的是,当调用 del
时调用它,如果该实例不是指针,而是从不同 C 函数 (Foo_init_value
) 返回的实际值。
如何获得 __del__
方法来调用指向从 C 中的函数返回的结构的指针?
在 Python 中:
import ctypes
import gc
libfoo = ctypes.CDLL("libfoo.so")
class Foo(ctypes.Structure):
_fields_ = [
('a', ctypes.c_int),
('b', ctypes.POINTER(ctypes.c_char)),
]
def __del__(self):
print('deleting')
libfoo.Foo_destroy(self)
# Get a pointer to Foo
libfoo.Foo_init.restype = ctypes.POINTER(Foo)
libfoo.Foo_init.argtypes = None
# Get actual Foo, not pointer
libfoo.Foo_init_value.restype = Foo
libfoo.Foo_init_value.argtypes = None
libfoo.Foo_destroy.restype = ctypes.c_int
libfoo.Foo_destroy.argtypes = [ctypes.POINTER(Foo)]
# Get a pointer to Foo
foo = libfoo.Foo_init()
# Nothing is printed here:
del foo
# Nothing is printed here
gc.collect()
# Nothing is printed here
[f for f in gc.get_objects() if isinstance(f, Foo)]
# Get an actual Foo, not pointer
foo = libfoo.Foo_init_value()
# This works, prints 'deleting', but crashes with freeing an invalid pointer
# presumably because __del__ is passing the struct, not pointer to struct
del foo
这是我的琐碎 C 库:
#include <stdlib.h>
typedef struct Foo
int a;
char *b;
Foo;
/* Allocate and return pointer to Foo */
/* __del__ does not work for this one */
Foo *Foo_init(void)
Foo *foo = (Foo *) malloc(sizeof(Foo));
foo->a = 0;
foo->b = NULL;
return foo;
/* Allocate and return value of Foo, not a pointer*/
/* __del__ works on this */
Foo Foo_init_value(void)
Foo *foo = Foo_init();
return *foo;
int *Foo_destroy(Foo *foo)
if (foo->b)
free(foo->b);
foo->b = NULL;
free(foo);
return 0;
编译:
gcc -c -Wall -Werror -fpic foo.c
gcc -shared -o libfoo.so foo.o
【问题讨论】:
什么已经解决,什么可以改变?关于.dll,函数签名可以修改吗? @CristiFati 函数签名无法更改;它们来自供应商提供的专有/旧版 API。 【参考方案1】:这可行,但我认为有更好的方法:
Foop = ctypes.POINTER(Foo)
def foo_del(self):
print('deleting')
libfoo.Foo_destroy(self)
Foop.__del__ = foo_del
foo = libfoo.Foo_init()
# prints 'deleting'
del foo
【讨论】:
以上是关于没有为指向结构的指针调用 ctypes.Structure 子类的 ctypes __del__的主要内容,如果未能解决你的问题,请参考以下文章
Core Data 实体中的可转换属性可以是指向 c 结构的指针吗?我的变压器没有被调用