return a ctypes object to C

Thomas Jollans tjol at tjol.eu
Thu Oct 31 09:44:30 EDT 2019


On 31/10/2019 14.13, Arnaud Loonstra wrote:
> On 30-10-2019 09:32, Arnaud Loonstra wrote:
>> Hi all,
>>
>> I'm trying to wrap my head around the ctypes API. I have a C
>> structure I wish to create in Python and then return from python to C.
>>
>> So a python method is called from C and needs to return an object
>> which we then process in C again.
>>
>> I have a binding to access and create the C methods and structures so
>> in Python I can call the Zmsg() constructor. I now need to return this.
>>
>> My python test method is simply:
>>
>> def actor_test( *args, **kwargs):
>>      print("test")
>>      msg = Zmsg()
>>      frame = Zframe(b"Hello", 5)
>>      msg.prepend(frame)
>>      return msg
>>
>> the method is called from C as follows:
>>
>> PyObject *pReturn = PyObject_CallObject(pFunc, NULL);
>>
>> This correctly calls the method. However the returned object is of
>> course a PyObject*. The debugger says it's
>>
>> "<czmq._czmq_ctypes.Zmsg object at 0x7ffff5f18e50>"    PyObject
>>              [class]    "<class 'czmq._czmq_ctypes.Zmsg'>"
>>              [super class]    "<class 'object'>"
>>              [meta type]    "<class 'type'>"
>>              ob_refcnt    1    Py_ssize_t
>>
>> However how I can I get it back to the original C type (zmsg_t *)
>>
>> Any help really appreciated.
>>
>
> What I've found so far is that I can return the address of the ctypes
> object.
>
> msg = Zmsg()
> frame = Zframe(b"Hello", 5)
> msg.prepend(frame)
> return addressof(msg._as_parameter_.contents)
>
> In C I can then cast it back to the original type.
>
> PyObject *pReturn = PyObject_CallObject(pFunc, NULL);
> assert(pReturn);
> long bla = PyLong_AsLong(pReturn);
> zmsg_t* test = (zmsg_t *)bla;
> assert(test);
> char *hello = zmsg_popstr(test);
> assert(hello);
> assert(streq(hello, "Hello"));
>
> This works, I'm not sure if this is the right way. It also creates a
> complicated setup with the garbage collector.
>
> Anybody better ideas?

You've already got a complicated setup with your ctypes objects...

If you're using the Python C API anyway, why would you use ctypes at
all? You can create custom Python types in C to wrap your C pointers.

Alternatively: if you're using ctypes anyway, why use the Python C API
at all? You can create C function pointers from Python functions with
ctypes.

If you're mixing two different ways of interfacing Python and C, the
result will ALWAYS be messy. Better to stick to one. Personally, I
prefer cffi or cython depending on the situation, as I find them clearer
and easier to use than ctypes. Using the Python C API directly is
usually the hardest to understand and the easiest to get wrong.

-- Thomas





More information about the Python-list mailing list