[Pyrex] Pyrex and char *x[]

Matt Hammond matt.hammond at rd.bbc.co.uk
Wed May 16 10:09:25 UTC 2007


Oops, I forgot to allocate memory for the destination to which the string  
is being copied!

Add this header import:

     cdef extern from "stdlib.h":
         cdef void *malloc(int)

Then just before the memcpy call:

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

Rather amusing after harping on about being careful about memory  
allocation and garbage collection :-)

Matt

On Wed, 16 May 2007 09:33:29 +0100, Matt Hammond  
<matt.hammond at rd.bbc.co.uk> wrote:

> 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