我有一个如下所示的代码:
from ctypes import *
import some_library
class Thing(Structure):
_fields_ = [
("A", c_uint8*4),
("B", Group*4)]
pointer_to_thing = POINTER(Thing)()
def get_thing():
some_library.allocate_memory_for_thing()
some_library.read_thing()
pointer_to_thing = some_library.give_me_the_thing()
thing = pointer_to_thing.contents
some_library.release_memory()
return thing
thing = get_thing()
失败了,因为
some_library.give_me_the_thing()
给了我对该事物的引用,而 some_library.release_memory()
正在释放该事物所在的内存。如果我评论some_library.release_memory()
它可以工作,但这不是它应该如何完成的。我必须在从函数返回之前释放内存,因此我想复制该内容并返回该副本,如下所示:
def get_thing():
some_library.allocate_memory_for_thing()
some_library.read_thing()
pointer_to_thing = some_library.give_me_the_thing()
thing = pointer_to_thing.contents
copy_of_thing = Thing()
memmove(
addressof(copy_of_thing),
addressof(thing),
sizeof(Thing),
)
some_library.release_memory()
return copy_of_thing
但是,它总是返回不正确数据的
Thing
。如果 some_library.release_memory()
被注释,那么它会按预期工作。就好像根本没有复制内容一样……
我也尝试过
def get_thing():
some_library.allocate_memory_for_thing()
some_library.read_thing()
pointer_to_thing = some_library.give_me_the_thing()
thing = pointer_to_thing.contents
copy_of_thing = Thing.copy_from_buffer(thing)
some_library.release_memory()
return copy_of_thing
行为是完全相同的,即如果我释放内存,它就会失败,如果我不释放它,它就会工作。
不幸的是
some_library
是一件复杂的事情,我无法轻松创建一个MWE来发布在这里。
只要您的对象是连续内存并且不包含指向其他已分配内存的指针,
.from_buffer_copy()
就应该可以工作。一个简单的演示:
import ctypes as ct
crt = ct.CDLL('msvcrt')
crt.malloc.argtypes = ct.c_size_t,
crt.malloc.restype = ct.c_void_p
crt.free.argtypes = ct.c_void_p,
crt.free.restype = None
class Thing(ct.Structure):
_fields_ = (('a', ct.c_uint8 * 4),
('b', ct.c_uint8 * 4))
def __repr__(self):
return f'Thing(a={bytes(self.a)}, b={bytes(self.b)})'
# A "C" malloc and init of some memory and
# build a thing simulating returning a
# malloc-ed object from C
s = crt.malloc(8)
ct.memmove(s, b'1234abcd', 8)
thing1 = Thing.from_address(s)
thing2 = Thing.from_buffer(thing1) # references existing memory
thing3 = Thing.from_buffer_copy(thing1) # makes a copy
# fill the memory with a deleted pattern, then free it.
ct.memmove(s, b'\xdd' * 8, 8)
crt.free(s)
print(thing2)
print(thing3)
输出:
Thing(a=b'\xdd\xdd\xdd\xdd', b=b'\xdd\xdd\xdd\xdd')
Thing(a=b'1234', b=b'abcd')