bbcannon [10/06/02 10:35 -0600]:
> I do know the size of the array before hand since I create it in perl
> first.  I am a rookie when it comes to C, so thanks a million.

Right... I meant the C compiler needs to know at compile time. Even if you
know, that doesn't mean it will know. For example,

----8<----
use strict;
use constant SIZE => 10;
use Inline C => <<'END';
    AV*
    mkary(int size) {
        double foo[size];
    }
END
mkary(SIZE);
---->8----

That will be a compile error. Even though it's obvious to humans that the
array "foo" will always have 10 elements in it, the C compiler doesn't know
where "size" is coming from, so it doesn't know how big to make foo when it's
compiling it.

> In the Big Picture, I am just trying to pass a perl array
> to C because I can then interface to Matlab's Math and Graphics libraries.  

One way to get around this is to dynamically generate your C
code. But a much simpler way is what I've already suggested.

> Is there a more efficient/easy way to send an array or array_ref to Inline
> C?

This is the best way to do it, I think. The only thing you have to check is
that you only accept arrays with numeric types. No nested structures (unless
you add code for that explicitly).

Note: I haven't tried this code, but it looks okay. You probably want to do
something like it. The API leaves something to be desired: it takes an
arrayref and returns a list... but you get the idea.

----8<----
use Inline C;

my @array = (10, 11, 12);
my @xformed = do_something(\@array);

__DATA__
__C__

void
transform_array(SV* ref) {
    int i, nelems;
    double *c_ary;
    AV *ary;

    if (SvROK(ref) && SvTYPE(SvRV(ref)) == SVt_PVAV) {
        ary = (AV*)SvRV(ref);
        nelems = av_len(ary) + 1;
        New(0, c_ary, nelems, double);
        SAVEFREEPV(c_ary);
        
        for (i = 0; i < nelems; ++i) {
            SV *elem, **tmp = av_fetch(ary, i, 0);
            if (!tmp)
                croak("Error fetching array index %i", i);
            elem = *tmp;
            c_ary[i] = SvNV(elem);
        }

        /* Operate on c_ary here. Do whatever it is you need to do */
        matlab_foozle(c_ary, nelems);

        /* Depending on your application, you could either save the values of
         * 'c_ary' back into 'ref', or you can build a new list to return to
         * the application. */
        for (i = 0; i < nelems; ++i)
            XPUSHs(sv_2mortal(newSVnv(c_ary[i])));
        XSRETURN(nelems);
    }
    else
        croak("Not an array ref");
}
---->8----

Later,
Neil

Reply via email to