[Pyrex] Functions pointers

Robert Bradshaw robertwb at math.washington.edu
Fri Apr 11 11:44:26 CEST 2008


On Apr 11, 2008, at 2:12 AM, Daniele Pianu wrote:
> I'm trying to wrap a C function that requires a C function pointer  
> as argument. I've wrote a pyrex extension with a dictionary where  
> every key is a C function name, and every entry is a C function  
> pointer, stored as a long. I call the C function from python  
> passing the function name and the necessary data.
>
> An example:
>
> -------- c_funcs.h ---------
>
> int returnFoo(int);
>
> int returnBar(int*);
>
> char* returnFooBar(char*);
>
> int callFoo(int(*)(int), int);
>
> int callBar(int(*)(int*), int*);
>
> char* callFooBar(char*(*)(char*), char*);
>
>
> ------- c_funcs.c -------
> #include <c_funcs.h>
>
> int returnFoo(int foo){
>   return foo;
> }
>
> int returnBar(int* bar){
>   if (bar)
>     return *bar;
> }
>
> char* returnFooBar(char* fooBar){
>   if (fooBar)
>     return fooBar;
> }
>
> int callFoo(int(*func)(int), int foo){
>   return (*func)(foo);
> }
>
> int callBar(int(*func)(int*), int* bar){
>   return (*func)(bar);
> }
>
> char* callFooBar(char*(*func)(char*), char* FooBar){
>   return (*func)(FooBar);
> }
>
> ------- funcs.pyx ----------
> cdef extern from "c_funcs.h":
>   int callFoo(int(*)(int), int)
>   int callBar(int(*)(int*), int*)
>   char* callFooBar(char*(*)(char*), char*)
>
> cdef class funcs:
>   cdef object funcsDict
>   def __init__(self):
>       cdef unsigned long fooPointer
>       fooPointer = <unsigned long>&callFoo
>       self.funcsDict = {}
>       self.funcsDict['returnFoo'] = fooPointer
>       # Here the python interpreter prints an integer, not a long  
> as expected!!!

Python ints are c longs, which may not actually be the size of  
pointers on all systems.

>       print self.funcsDict['returnFoo']
>
>   def pyCallFoo(self, foo):
>       # The call to C function produces a Segmentatio Fault
>       return callFoo(<int(*)(int)>self.funcsDict['returnFoo'], foo)

self.funcsDict['returnFoo'] returns a PyObject* (that points to a  
Python int), and it is the memory location of the object that you are  
casting to an int(*)(int).

In Cython you can write

     return callFoo(<int(*)(int)><long>self.funcsDict['returnFoo'], foo)

to force it to unpack the Python long. With in Pyrex you need an  
extra variable

     cdef long my_temp_var
     my_temp_var = self.funcsDict['returnFoo']
     return callFoo(<int(*)(int)>my_temp_var, foo)

Just make sure no one messes with your dictionary!

>
>
> How can I solve the problem? Every advice about alternative  
> implementation is also appreciated :)






More information about the Pyrex mailing list