I've been messing around with Inline and XS recently to speed up some particularly slow routines in my roguelike engine. Some of the routines involve taking in arguments and returning them. When I started to get really strange segfault errors, I decided to reduce the code to a simple test case. When I did, I found out that it's difficult to take in a variable number of arguments and pass back multiple return values in the same C subroutine with XS macros. I'm sure that there is a way; I just have not yet discovered it. Could anybody please point me in the right direction?
#!/usr/bin/perl package perlicious; use strict; use warnings; use Data::Dumper; use Inline C => 'DATA', CCFLAGS => '-g', CLEAN_AFTER_BUILD => 0; sub debug { print Dumper([@_]), "\n" } print ">>>Calling in...<<<\n"; in("smack", 16, "that", "fool"); print "\n>>>Calling out...<<<\n"; debug out("smack", 16, "that", "fool"); print ">>>Calling combo...<<<\n"; debug buggy("smack", 16, "that", "fool"); # This just returns a list of numbers sub perlish { my $num = shift; my @ls; push @ls, "numba $_" foreach 1 .. $num; return @ls; } __DATA__ __C__ // All of this probably could be written better. I'm new to C and XS. +Critique // welcome. // This tests taking in a variable amount of arguments. Works fine. void in (char *first, ...) { SV *gotin[10]; int passed; dXSARGS; sp = mark; passed = items; int i; for (i = 0; i < items; i++) { gotin[i] = newSVsv( ST(i) ); } PUTBACK; int cntr; for (cntr = 0; cntr < passed; cntr++) { printf("gotin: %s\n", SvPV_nolen( gotin[cntr] )); } } // This demonstrates calling a perl sub and returning its results to p +erl. The // reason for the separate blocks is to avoid clashes with the macros +that set // up the stack variables. This is also why the temporary array gotbac +k is // needed. void out (SV* useless, ...) { SV *gotback[10]; int returned; if (1) { dSP; I32 ax; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs( sv_2mortal( newSViv(7) ) ); PUTBACK; returned = call_pv("perlish", G_ARRAY); printf("expect %d args\n", returned); SPAGAIN; SP -= returned; ax = (SP - PL_stack_base) + 1; int cnt; // Somehow store the return values. We need an array of SV*s. for (cnt = 0; cnt < returned; cnt++) { gotback[cnt] = newSVsv( ST(cnt) ); } PUTBACK; FREETMPS; LEAVE; } // Finally push the crap onto our return stack. if (1) { dXSARGS; sp = mark; int cnt; for (cnt = 0; cnt < returned; cnt++) { XPUSHs( gotback[cnt] ); } PUTBACK; return; } } // This tries to combine the two by taking a variable amount of argume +nts in // and returning a variable amount to perl. The input bit works, but t +he output // does not. (perl doesn't get any return values back on the stack.) T +his is // undoubtedly due to the fact that I use the dXSARGS, sp=mark, etc se +tup bit // twice. I don't know how to get around this. Help? // The solution may lie in the SPAGAIN, ENTER, LEAVE, etc macros which + some of // the documentation mentions. I'll get around to experimenting with t +hose // later. In the meantime, does anybody know exactly what to do? void buggy (char *first, ...) { // Tough to get around. Max arguments we can get back from a perl fu +nction // is gonna be 10. sorry. // Same for max we can take in here. SV *gotin[10]; SV *gotback[10]; int returned, passed; // First print args. Make sure I've got em! if (1) { dXSARGS; sp = mark; passed = items; int i; for (i = 0; i < items; i++) { gotin[i] = newSVsv( ST(i) ); } PUTBACK; int cntr; for (cntr = 0; cntr < passed; cntr++) { printf("gotin: %s\n", SvPV_nolen( gotin[cntr] )); } } if (1) { dSP; I32 ax; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs( sv_2mortal( newSViv(7) ) ); PUTBACK; returned = call_pv("perlish", G_ARRAY); printf("expect %d args\n", returned); SPAGAIN; SP -= returned; ax = (SP - PL_stack_base) + 1; int cnt; // Somehow store the return values. We need an array of SV*s. for (cnt = 0; cnt < returned; cnt++) { gotback[cnt] = newSVsv( ST(cnt) ); } PUTBACK; FREETMPS; LEAVE; } // Finally push the crap onto our return stack. if (1) { dXSARGS; sp = mark; int cnt; for (cnt = 0; cnt < returned; cnt++) { XPUSHs( gotback[cnt] ); } PUTBACK; return; } }

In reply to Inline/XS multiple input and output parameters by dabreegster

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.