5

Is it possible with ctypes to make pointer arithmetic?

First, let me show you what I'm trying to do in C

#include <stdio.h>

struct Foo {
 short *Bar;
 short *end_Bar;
};

int main() {
  short tab[3] = {1,2,3};
  struct Foo foo;
  foo.Bar = tab;
  foo.end_Bar = foo.Bar + 2; // Pointer arithmetic
  short *temp = foo.Bar;
  while(temp != foo.end_Bar)
    printf("%hi", *(temp++));
  printf("%hi", *(foo.end_Bar));
  return 0;
}

Now you understand that what I'm doing is creating an array of integer, and keeping in reference two pointers in a structure. One pointer at the begining and one at the end, instead of keeping the first pointer and the length of the array.

Now in Python I have an object that inherit from ctypes.Structure and as two members which are ctypes.POINTER(ctypes.c_short) type.

import ctypes

class c_Foo(ctypes.Structure):
    _fields_ = [
       ("Bar", ctypes.POINTER(ctypes.c_short)),
       ("end_Bar", ctypes.POINTER(ctypes.c_short))
    ]

if __name__ == "__main__":
    tab = [1,2,3]
    foo = c_Foo()
    foo.Bar = (c_short * len(tab))(*tab)
    foo.end_Bar = foo.Bar + 2 # TypeError, unsupported operand

So now the question. Is it possible to do pointer arithmetic with ctypes? I know that you can access value of the array by it index, but I don't want that, because I don't want a length reference in my structure.

7
  • Why? What do you gain by doing this? Commented Jun 21, 2017 at 19:58
  • 1
    It's not about why, but how. This is a simple example to demonstrate what I want, not what I do. Commented Jun 21, 2017 at 20:00
  • I disagree... this seems like an XY Problem to me. Commented Jun 21, 2017 at 20:01
  • How is this related to the C language? How you do something in C is completely irrelevant how to do it in Python. I agree with @TemporalWolf: This is an XY problem. Commented Jun 21, 2017 at 20:04
  • 3
    Pointer arithmetic isn't implemented, but you can index a pointer. The problem here is that this calls the getfunc, which for a simple type such as c_short automatically converts the indexed value to a Python integer. This behavior is disabled for subclasses of simple types, since it's assumed that you need to preserve the derived type. So if use a subclass of c_short, then you could use ctypes.pointer(foo.Bar[2]). There are other options, but it gets increasingly cumbersome. Commented Jun 21, 2017 at 20:05

1 Answer 1

8

It's convoluted, but this computes a c_short object at a byte offset in tab that shares its buffer, then gets a pointer to it:

from ctypes import *

class c_Foo(Structure):
    _fields_ = [
       ("Bar", POINTER(c_short)),
       ("end_Bar", POINTER(c_short))
    ]

tab = (c_short*3)(1,2,3)
foo = c_Foo()
foo.Bar = tab
foo.end_Bar = pointer(c_short.from_buffer(tab,sizeof(c_short)*2))
print(tab[2])
print(foo.Bar[2])
print(foo.end_Bar[0])
tab[2] = 4
print(tab[2])
print(foo.Bar[2])
print(foo.end_Bar[0])
3
3
3
4
4
4
Sign up to request clarification or add additional context in comments.

1 Comment

I think the next step for me, if using a subclass of c_short isn't an option, would be to use a pointer to a unit-length array, e.g. foo.end_Bar = POINTER(tab._type_ * 1)(tab)[2]. If tab is no longer available you can use foo.end_Bar = POINTER(foo.Bar._type_ * 1)(foo.Bar.contents)[2].

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.