no classification
no tag
no datas
posted on 2024-12-02 22:11 read(92) comment(0) like(0) collect(0)
In Python I'm using ctypes to exchange data with a C library, and the call interface involves nested pointers-to-structs.
If the memory was allocated from in C, then python should (deeply) extract a copy of any needed values and then explicitly ask that C library to deallocate the memory.
If the memory was allocated from in Python, presumably the memory will be deallocated soon after the corresponding ctypes object passes out of scope. How does this work for pointers? If I create a pointer object from a string buffer, then do I need to keep a variable referencing that original buffer object in scope, to prevent this pointer from dangling? Or does the pointer object itself automatically do this for me (even though it won't return the original object)? Does it make any difference whether I'm using pointer
, POINTER
, cast
, c_void_p
, or from_address(addressof)
?
Nested pointers to simple objects seem fine. The documentation is explicit that ctypes doesn't support "original object return", but implies that the pointer does store a python-reference in order to keep-alive its target object (the precise mechanics might be implementation-specific).
>>> from ctypes import *
>>> x = c_int(7)
>>> triple_ptr = pointer(pointer(pointer(x)))
>>> triple_ptr.contents.contents.contents.value == x.value
True
>>> triple_ptr.contents.contents.contents is x
False
>>> triple_ptr._objects['1']._objects['1']._objects['1'] is x # CPython 3.5
True
Looks like the pointer function is no different to the POINTER template constructor (like how create_string_buffer
relates to c_char * size
).
>>> type(pointer(x)) is type(POINTER(c_int)(x))
True
Casting to void also seems to keep the reference (but I'm not sure why it modifies the original pointer?).
>>> ptr = pointer(x)
>>> ptr._objects
{'1': c_int(7)}
>>> pvoid = cast(p, c_void_p)
>>> pvoid._objects is ptr._objects
True
>>> pvoid._objects
{139665053613048: <__main__.LP_c_int object at 0x7f064de87bf8>, '1': c_int(7)}
>>> pvoid._objects['1'] is x
True
Creating an object directly from a memory buffer (or address thereof) looks more fraught.
>>> v = c_void_p.from_buffer(triple_ptr)
>>> v2 = c_void_p.from_buffer_copy(triple_ptr)
>>> type(v._objects)
<class 'memoryview'>
>>> POINTER(POINTER(POINTER(c_int))).from_buffer(v)[0][0][0] == x.value
True
>>> p3 = POINTER(POINTER(POINTER(C_int))).from_address(addressof(triple_ptr))
>>> v2._objects is None is p3._objects is p3._b_base_
True
Incidentally, byref probably keeps-alive the memory it references.
>>> byref(x)._obj is x
True
Author:qs
link:http://www.pythonblackhole.com/blog/article/247243/4f517cc6e8cd7930921c/
source:python black hole net
Please indicate the source for any form of reprinting. If any infringement is discovered, it will be held legally responsible.
name:
Comment content: (supports up to 255 characters)
Copyright © 2018-2021 python black hole network All Rights Reserved All rights reserved, and all rights reserved.京ICP备18063182号-7
For complaints and reports, and advertising cooperation, please contact vgs_info@163.com or QQ3083709327
Disclaimer: All articles on the website are uploaded by users and are only for readers' learning and communication use, and commercial use is prohibited. If the article involves pornography, reactionary, infringement and other illegal information, please report it to us and we will delete it immediately after verification!