2

For various reasons I would like to update the value of a ctypes pointer in place. In other words, what I want is to modify the internal buffer the pointer object wraps. Here is one possible approach:

from ctypes import *

a = pointer(c_int(123))
b = pointer(c_int(456))

memmove(addressof(a), addressof(b), sizeof(c_void_p))
a._objects.clear()
a._objects.update(b._objects)

Now a.contents will return c_long(456). However, playing around with the _objects attribute seems like it's too concerned with the implementation details (will this even behave correctly?). Is there a more idiomatic way to do this?

Bach
  • 6,145
  • 7
  • 36
  • 61
hetman
  • 919
  • 6
  • 16

2 Answers2

3

Since eryksun hasn't posted up his answer I'll add it here my self. This is how it should be done:

from ctypes import *

a = pointer(c_int(123))
b = pointer(c_int(456))

tmp = pointer(a)[0]
tmp.contents = b.contents

Now a.contents = c_int(456). The key is that tmp shares a buffer with a (which is why you'll find tmp._b_needsfree_ == 0).

hetman
  • 919
  • 6
  • 16
  • So what is the point of using `tmp`? Why not just `a.contents = b.contents`? – CiaranWelsh Jan 27 '21 at 15:00
  • @CiaranWelsh that would have assigned the pointer `a` to point to the same location as the pointer `b` does, which is not what we want here. We want a pointer that shares a buffer with `a` but doesn't change `a`'s buffer location when assigned. – hetman Feb 08 '21 at 04:21
0

A pointer is a variable that holds a memory address, so the call memmove(addressof(a), addressof(b),...) actually copies the address held by b into a so a now points at the same memory location that b points to. If that is what you desire, you're done.

If what you want is to set the value of the integer pointed to by a to the same value as that of the integer pointed to by b, then what you need is to copy the contents of the memory at the address pointed to by b into the memory pointed to by a. Like so...

memmove(cast(a, c_void_p).value, cast(b, c_void_p).value, sizeof(c_int))

now the pointer a points to a memory address that holds a value similar to the value stored at the memory pointed to by b.

the _objects attribute is not necessary in both cases (IMHO)

Sorry for the boring post. But that I'm afraid is the (only?) way to do pointers :)

  • 1
    `memmove` doesn't update the `_objects` dict, so the referent could be garbage collected. Use `a.contents = b.contents` to copy the pointer address and update the `_objects` dict. – Eryk Sun Apr 02 '14 at 11:14
  • What I'm trying to do is the former. That is, have both pointers point to the same place. The reason why this is useful is because in my actual use case, pointer `a` does not own its own buffer, but rather is a wrapper around the buffer of another object. This way I can automatically change the pointer in the parent object too. – hetman Apr 02 '14 at 11:21
  • 3
    @hetman, Do you mean something like this? `s = pointer(c_int(123)); b = pointer(c_int(456)); a = pointer(s)[0]`. In this case `a` doesn't own memory, i.e. `a._b_needsfree_ == 0`. Assigning `a.contents = b.contents` stores the address to the memory owned by `s`. After the assignment `s[0] == 456`. Using `contents` or dereferenced assignment by subscript (e.g. `a[0] = 456`) is necessary to allow ctypes to manage `_objects` and `_b_base_`, which keep an object alive when the memory it owns is referenced by other objects. – Eryk Sun Apr 03 '14 at 08:43
  • @eryksun: Yes, that's exactly what I needed but couldn't figure out how to get the double pointer thing working with ctypes. If you want to add that as an answer I'll mark it as the correct answer. – hetman Apr 07 '14 at 08:15