[Pyrex] Pyrex and char *x[]

Matt Hammond matt.hammond at rd.bbc.co.uk
Wed May 16 08:33:29 UTC 2007


On Wed, 16 May 2007 06:29:41 +0100, Georg Grabler <ggrabler at gmail.com>  
wrote:

> Hello everybody.
>
> I want an array to be passed to a function, so basically i started the
> function as follows:
>
> def addToList (self, char *array[]):
>   ....
>
> This throws an error compiling:
> "Cannot convert Python object argument to type 'char(*(*))'"

Functions and classes defined python style (without a "cdef" prefix) are  
made available to python and therefore can only deal with python objects -  
which c-style arrays are not. Similarly c-style strings are not the same  
as python strings.

Could you give a simple example of how you would use addToList from  
python? Would you be passing it something like a list or tuple, or using a  
library defined specialist array type?

Assuming you'd be passing it a list/tuple, eg:

     items=["hello","doctor","yesterday","tomorrow","continue"]
     X.addToList(items)

There is also the complication, since you're dealing with strings, of  
handling garbage collection issues: if you don't copy the string data out  
of the python string object, you need to inform python that you're still  
using that object, otherwise it may get garbage collected and the storage  
containing the string might be re-used!

Of course, the simplest, though not necessarily most efficient, solution  
is to copy the string data out of the string into a newly allocated  
character array.

If you want to declare c datatypes, or functions with c datatype  
arguments, then they need to be prefixed with cdef; and they will not be  
accessible from python (the specific variables, functions or classes  
declared with cdef)


Here's roughly what I end up doing (in the .pyx file):


     cdef extern from "string.h":
         cdef void *memcpy(void *, void *, int)


     class MyClass:

         def addToList(self, listitems):
             cdef char *cString
             cdef char *copy
             cdef int length

             for pyString in listitems:
                 cString = pyString        # pyrex auto converts
                 length = len(pyString)

                 # now make our own copy of the string data
                 copy = memcpy(copy, cString, length)

                 self.addList(copy)


         cdef addList(self, char *str):
             # your code

Caveat: I've not tested this code above; but as I said, I've found this  
general approach works for me.

Remember python string's don't use null termination conventions, so if  
you're retrieving them from your list for later use, you probably also  
need to store the length of the string somewhere too. Hope that's not  
teaching you to suck eggs :-)


Hope this helps


Matt
-- 
| Matt Hammond
| Research Engineer, FM&T, BBC, Kingswood Warren, Tadworth, Surrey, UK
| http://kamaelia.sf.net/
| http://www.bbc.co.uk/rd/



More information about the Pyrex mailing list