Increment a float pointer in Python

73 Views Asked by At

I have a float pointer p from a C++ library which I want to increment in a Python module. When I try to write p + distance, I'm receiving the error that the operator + would be undefined for LP_c_float.

A possible solution is to use advance(p, distance) instead, where

def advance(pointer, distance, type = ctypes.c_float):
    return ctypes.cast(ctypes.cast(pointer, ctypes.c_voidp).value + distance, ctypes.POINTER(type))

However, is the cast to ctypes.c_voidp really necessary? Why addition is not defined for LP_c_float (or why doesn't it have a similar value field)?

1

There are 1 best solutions below

4
Mark Tolonen On BEST ANSWER

There isn't a direct way to increment a pointer, just the value that the pointer points to. You can use simple indexing to get the next values as shown below.

Assuming you have a float* to the first element of an array of data, p below is the equivalent:

import ctypes as ct

data = (3 * ct.c_float)(1.5, 2.5, 3.5) # (C) float data[3] = {1.5, 2.5, 3.5};
p = ct.POINTER(ct.c_float)(data)  # (C) float* p = data;
print(p, p[0], p[1])
p[0] += 1
p[1] += 2
print(p, p[0], p[1])
p.contents.value += 2  # (C) *p += 1
print(p, p[:len(data)]) # If you know the length, slice data into Python list

Output:

<__main__.LP_c_float object at 0x0000019FA3E116D0> 1.5 2.5
<__main__.LP_c_float object at 0x0000019FA3E116D0> 2.5 4.5
<__main__.LP_c_float object at 0x0000019FA3E116D0> [4.5, 4.5, 3.5]

To actually increment the pointer itself you have to jump through hoops. Below increments the pointer by one element, e.g. in C: p += 1.

# Get the C address of the first element (Python int)
# and add the size of an element in bytes.
new_address = ct.addressof(p.contents) + ct.sizeof(ct.c_float)
# c_void_p() takes a Python int for initialization.
# Other pointers don't, so a cast is needed.
p = ct.cast(ct.c_void_p(new_address), ct.POINTER(ct.c_float))
print(p, p[:2])

Output:

<__main__.LP_c_float object at 0x0000019FA3E10F50> [4.5, 3.5]

As you can see this is expensive. Do the pointer math in C instead if you have to.