2

I have Perl Code and C Code and I am calling C functions in my Perl Code. I have passed a float array from Perl to C by packing it (like this http://www.perlmonks.org/?node_id=39697) and it works nicely!

my $p_angle = pack("f*", @angle);

But now I am trying to return that array from my C function to Perl and I want to be able to do stuff with it, e.g read values, print...

I have tried to unpack it with

my @array = unpack("f*", $entropy);

but that does not work at all, I always see the same not reasonable values when I print the @array.

So I guess I am doing it wrong, does anybody know how to unpack the array properly?

Jen Mer
  • 101
  • 1
  • 3
  • 10
  • 3
    1) We can't really say what's wrong, without the XS code to look at. There's nothing wrong per se about the unpack. 2) That post is pretty bad advice IMO, and if you're trying to follow it straightforwardly for return values, you're probably making memory management mistakes. I would really suggest doing things the normal way, on the stack. – hobbs Aug 29 '17 at 15:21
  • 1
    The post calls a C function from perl that takes `char *` as an argument, which works well enough. The reverse -- passing `char *` from C to Perl -- is trickier because Perl will stop reading when it encounters a NULL (`\0`) in the C output. – mob Aug 29 '17 at 15:26
  • 2
    We can't tell what you mistake you've made because you didn't show your code. Please provide a minimal, runnable demonstration of the problem. – ikegami Aug 29 '17 at 15:53
  • @mob, Re "*is trickier because Perl will stop reading when it encounters a NULL (\0) in the C output.*", No. It reads as many as you specify. `newSVpv((char*)array, num_ele*sizeof(array[0]))` – ikegami Aug 29 '17 at 16:09
  • 1
    I'm saying that for an XS function like `char* foobar() { return "foo\0bar\0" }`, a Perl call to `foobar()` will receive the string `foo`. – mob Aug 29 '17 at 16:20
  • @mob, Well yeah, but you shouldn't *ever* use `char*` as the type of arguments or return value in XS. (Well, you could use it if you can guarantee ASCII, but that's it.) So, I repeat, there's no problems with NULs in XS. Quite the opposite, XS is actually capable of handling NULs in strings; it's C that can't. – ikegami Aug 29 '17 at 18:09

1 Answers1

4
use strict;
use warnings;
use feature qw( say );

use Inline C => <<'__EOS__';

#include <stdio.h>

SV* test(SV* sv) {
   float* array;
   size_t num_eles;
   {
      STRLEN len;
      char* s = SvPVbyte(sv, len);
      num_eles = len/sizeof(float);

      /* We can't just cast s because we could */
      /* run afoul of alignment restrictions. */
      array = malloc(len);
      memcpy(array, s, len);
   }

   {
      size_t i;
      for (i=0; i<num_eles; ++i) {
         printf("%zu %.6f\n", i, (double)(array[i]));
      }
   }

   {
      SV* return_sv = newSVpv((char*)array, num_eles*sizeof(float));
      free(array);
      return return_sv;  /* The typemap will mortalize. */
   }
}

__EOS__

my @a = (1.2, 1.3, 1.4);
say sprintf "%u %.6f", $_, $a[$_] for 0..$#a;
my $a = pack('f*', @a);
my $b = test($a);
my @b = unpack('f*', $b);
say sprintf "%u %.6f", $_, $b[$_] for 0..$#b;
ikegami
  • 367,544
  • 15
  • 269
  • 518