[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