As for the "Attempt to free unreferenced scalar" warning, you can avoid that one of two ways.
You have to decide whether your XS algorithm is the equivalent of $a .= $b or $a = $a . $b. If there's a possibility that $a might be read-only, then your only choice is $a = $a . $b.
If you want $a .= $b, then your Inline C function should be a void function rather than returning an SV*. If you want $a = $a . $b, then you need to create a new scalar and return it.
You should not ever return the SAME scalar that was passed in. Right now, the scalar is having its reference count dropped twice -- once when you leave the XS function, and once when @_ is cleaned up after that function returns. That's why you have to increment it to avoid the freeing error. But you shouldn't do it that way -- you should either return a new scalar, or void.
Since you want the impossible (appending to read-only scalars), I can't supply a script which solves your problem, but here's one that hopefully points the way:
#!/usr/bin/perl use strict; use warnings; use Inline C => <<'END_C'; SV* concat(SV *a, SV *b) { SV *c; if (SvOK(a)) c = newSVsv(a); else c = newSVpvn("", 0); if (SvOK(b)) sv_catsv(c, b); return c; } void append(SV *a, SV *b) { if (!SvOK(a)) sv_setpvn(a, "", 0); if (SvOK(b)) sv_catsv(a, b); } END_C my @pairs = ( [ 'bill', undef ], [ 'bill', 'fred' ], [ undef, 'fred' ], [ 1, undef ], [ 1, 1 ], ); test($_) for @pairs; sub test { my $pair = shift; my $c = concat(@$pair); print "$c\n"; append(@$pair); print "$pair->[0]\n"; }
In reply to Re: XS/Inline::C concat *any* two SVs.
by creamygoodness
in thread XS/Inline::C concat *any* two SVs.
by BrowserUk
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |