I am trying to pass a struct back into my Python from a c file. Let's say I have a file pointc.c like this:
typedef struct Point {
int x;
int y;
} Point;
struct Point make_and_send_point(int x, int y);
struct Point make_and_send_point(int x, int y) {
struct Point p = {x, y};
return p;
}
Then I set-up a point.pyx file like this:
"# distutils: language = c"
# distutils: sources = pointc.c
cdef struct Point:
int x
int y
cdef extern from "pointc.c":
Point make_and_send_point(int x, int y)
def make_point(int x, int y):
return make_and_send_point(x, y) // This won't work, but compiles without the 'return' in-front of the function call
How do I get the returned struct into my Python? Is this kind of thing only possible by creating a struct in the Cython and sending by reference to a void c function?
As a reference, my setup.py is:
from distutils.core import setup, Extension
from Cython.Build import cythonize
setup(ext_modules = cythonize(
"point.pyx",
language="c"
)
)
Most typically you would write some kind of wrapper class that holds the c-level struct, for example:
# point.pyx
cdef extern from "pointc.c":
ctypedef struct Point:
int x
int y
Point make_and_send_point(int x, int y)
cdef class PyPoint:
cdef Point p
def __init__(self, x, y):
self.p = make_and_send_point(x, y)
@property
def x(self):
return self.p.x
@property
def y(self):
return self.p.y
In usage
>>> import point
>>> p = point.PyPoint(10, 10)
>>> p.x
10
Cython's default behaviour given a struct is to convert it to a Python dictionary, which may be good enough for you. (This only works for structs made up of simple types though).
There's a couple of reasons why this isn't working. First you should do cdef extern from
from headers, not source files, otherwise you get errors about multiple definitions (I assume this is just a mistake in creating your minimal example). Second you need to put the definition of Point
within your cdef extern
block:
cdef extern from "pointc.h":
cdef struct Point:
int x
int y
If you don't do that then Cython creates a mangled internal name for your struct (__pyx_t_5point_Point
) which doesn't match the C function signature and thus it fails.
With this corrected, you get the correct default behaviour of converting structs to dicts. (This should work both ways - you can convert dicts back to structs). In the event that this isn't what you want, follow @chrisb's answer
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With