David Christopher Asher wrote:
This works for dynamically allocating memory (an array of char):

SV * create_image(int size) {
    char * image;
    New(0,image,size,char);
    memset(image,CLEAR,size);
    return sv_setref_pv(newSViv(0),"image", (void *)image);
 }

void destroy_image(SV * p) {
    char * image = (char *) SvIV(SvRV(p));
    Safefree(image);
 }

And to access the memory as an array of char:

void clear_image(SV * p,int size) {
    char * image = (char *) SvIV(SvRV(p));
    memset(image,CLEAR,size);
 }


Yes, I had kept a copy of that from when you originally posted and was using that as a basis for my attempt. With some off-list assistance and the OOP example ('Soldier') in the cookbook, it's now working quite nicely. (First problem was that I was stupidly creating a reference to something that didn't exist - as Joe pointed out a little earlier today:-)



I would assume something similar would work for a struct, something along the lines of:

typedef struct {
    SV * suit;
    int value;
 } CARD;

SV * create_card(int size) {
    CARD * my_card;
    New(0,my_card,size,CARD);
    memset(my_card,CLEAR,size*sizeof(CARD));
    return sv_setref_pv(newSViv(0),"card", (void *)my_card);
 }


I only wanted one card (with 'suit' and 'value' supplied as function arguments so I have:


SV * create_card(SV * s, int v) {
     Card *cptr;
     New(1, cptr, sizeof(Card), Card);
     if(cptr == NULL) croak("Mem not allocated");
     cptr->suit = s;
     cptr->value = v;
     return sv_setref_pv(newSViv(0), Nullch, cptr);
     }

which would allocate memory for an array of cards (a 'deck' so to speak),
and return the pointer to the array.  I would have done a function to create
one card, but it would not have been any simpler.  And for whatever reason,
I have trouble getting Inline to properly recognize and bind functions that
pass no params (int myfunc(void)).


Try writing it as 'int myfunc() {}' rather than 'int myfunc(void) {}'


And to hand out cards from Perl:

void deal_card(SV * p,SV * suit,int value) {
    CARD * my_card = (CARD *) SvIV(SvRV(p));
    my_card->suit = suit;
    my_card->value = value;
    return;
 }

I'm not 100% sure on the "SvIV(SvRV(p))" part -- It's what works for an
array of char.


Seems to work just fine for 'Card' and for the GMP library structs (which is what I'm really doing).


Incidentally, there's a current (small) thread on this subject on the XS mailing list where Nick Ing-Simmons offers the following:

-----------------------------------------------
>Is it safe to store a pointer to a C struct in an SV?


Yes, provided the lifetime of the data pointed to is suitable.



> > MY_STRUCT my_struct; > sv = newSVuv((unsigned long) &my_struct); > SvIOK_only_UV(sv);


Your my_struct is on the stack in the XS function - memory gets reused when XS returns.

What I tend to do is put the struct in the string part of a SvPV

     SV *sv = newSV(sizeof(MY_STRUCT));
     MY_STRUCT *my_struct = (MY_STRUCT *) SvPVX(sv);



>
>and later on my_filter() can then access:
>
>    (MY_STRUCT *) SvUVX(sv)


That would in my scheme be


     MY_STRUCT *my_struct = (MY_STRUCT *) SvPVX(sv);
-----------------------------------------------

I haven't digested that yet :-)

Thanks David, Joe.

Cheers,
Rob

--
Any emails containing attachments will be deleted from my ISP's mail server before I even get to see them. If you wish to email me an attachment, please provide advance warning so that I can make the necessary arrangements.




Reply via email to