Perl Inline C: Passing Arrayref to C Function - perl

I can't get arrayrefs passed into a C function using Inline C. I would like some help, please.
First, just to prove I can get Inline C to work, I'll pass a scalar value to a C function:
#!/usr/bin/perl -I.
#
# try1.pl
#
use Inline C;
my $c = 3.8;
foo( $c );
__END__
__C__
void foo( double c )
{
printf( "C = %f\n", c );
}
And run it:
% ./try1.pl
C = 3.800000
Now do the same thing, but with an arrayref:
#!/usr/bin/perl -I.
#
# try2.pl
#
use Inline C;
my #abc = (1.9, 2.3, 3.8);
foo( \#abc );
__END__
__C__
void foo( double *abc )
{
printf( "C = %f\n", abc[2] );
}
Run it:
% ./try2.pl
Undefined subroutine &main::foo called at ./try1.pl line 7.
Any ideas what I'm doing wrong? Help greatly appreciated!

Inline::C is smart enough to extract values from SV's based on your C function's type signature. But if you want to pass complex Perl structures to C functions you'll need to use the Perl API to extract the values. So, here's what you need to know for this problem:
An array is an instance of a C struct called AV. A reference is implemented by a struct called an RV. All of these are "subtypes" (kinda) of a base struct called SV.
So to make this function work we need to do a few things.
Change the parameter type to SV * (pointer to an SV).
Use the API to check if this particular SV is a reference as opposed to some other kind of scalar
Check the RV to make sure it's pointing at an array and not something else.
Dereference the RV to get the SV that it points to.
Since we know that SV is an array, cast it to AV and start working with it.
Lookup the third element of that array, which is another SV.
Check that the SV we got from the array is a numerical value suitable for C printf
Extract the actual numerical out of the SV.
Print the message
So putting that all together, we get something like this:
use Inline C;
my #abc = (1.9, 2.3, 3.8);
foo( \#abc );
__END__
__C__
void foo( SV *abc )
{
AV *array; /* this will hold our actual array */
SV **value; /* this will hold the value we extract, note that it is a double pointer */
double num; /* the actual underlying number in the SV */
if ( !SvROK( abc ) ) croak( "param is not a reference" );
if ( SvTYPE( SvRV( abc ) ) != SVt_PVAV ) croak( "param is not an array reference" );
/* if we got this far, then we have an array ref */
/* now dereference it to get the AV */
array = (AV *)SvRV( abc );
/* look up the 3rd element, which is yet another SV */
value = av_fetch( array, 2, 0 );
if ( value == NULL ) croak( "Failed array lookup" );
if ( !SvNOK( *value ) ) croak( "Array element is not a number" );
/* extract the actual number from the SV */
num = SvNV( *value );
printf( "C = %f\n", num );
}
Kinda makes you appreciate how much work Perl does under-the-hood. :)
Now, you don't have to be as super-explicit as that example. You could get rid of some of the temp variables by doing things inline, e.g.
printf( "C = %f\n", SvNV( *value ) );
would eliminate the need to declare num. But I wanted to make it clear how much dereferencing and type-checking is needed to traverse a Perl structure in C.
And as #mob points out below, you don't actually have to do all that work (though it's a good idea to be familiar with how it works.)
Inline::C is smart enough that if you declare your function as
void foo( AV *abc ) {
...
}
It will automatically unwrap the AV for you and you can go straight to the av_fetch step.
If all of that seems baffling to you, I highly recommend taking a look at:
The Perlguts Illustrated PDF, then
The perlguts manpage, and then
The Inline::C Cookbook, while consulting
The perlapi manpage.

In your Inline::C code:
void foo( SV *reference ) {
AV *array;
array = (AV *)SvRV( reference );
...
}
Then deal with the array value as the AV type. See the Perl Inline::C Cookbook.

Wrong data type.
use Inline 'C';
my #abc = (1.9, 2.3, 3.8);
foo( \#abc );
__END__
__C__
void foo(SV* abc) {
sv_dump(abc);
}

Related

how to write a C function and be able to call it from perl

I have been programming C for a while. Now I need to write a C program that perl can call.
It should have the same syntax as the following dummy perl function: Take two inputs, both are strings (may contain binary characters, even "\x00"), output a new string.
Of course, algorithm of the function will be more complex, that's why I need to do it in C.
sub dummy {
my ($a, $b) = #_;
return $a . $b;
}
I have briefly looked at SWIG for the implementation, but taking input/ouput other than an integer is not easy, hope someone can give a concrete example.
Thanks in advance.
UPDATE: Got a great example from Rob (author of the Inline::C module in cpan), thanks!
##############################
use warnings;
use strict;
use Devel::Peek;
use Inline C => Config =>
BUILD_NOISY => 1,
;
use Inline C => <<'EOC';
SV * foo(SV * in) {
SV * ret;
STRLEN len;
char *tmp = SvPV(in, len);
ret = newSVpv(tmp, len);
sv_catpvn(ret, tmp, len);
return ret;
}
EOC
my $in = 'hello' . "\x00" . 'world';
my $ret = foo($in);
Dump($in);
print "\n";
Dump ($ret);
##############################
Perl has a glue language called XS for this kind of thing. It knows about mappings between Perl data types and C types. For example, a C function
char *dummy(char *a, int len_a, char *b, int len_b);
could be wrapped by the XS code
MODULE = Foo PACKAGE = Foo
char *
dummy(char *a, int length(a), char *b, int length(b));
The Foo.xs file will be compiled when the module is installed, all relevant build tool chains have support for XS.
Argument conversion code will be generated automatically, so that the function can be called in Perl as Foo::dummy("foo", "bar"), once the XS code has been loaded from Perl:
package Foo;
use parent 'DynaLoader';
Foo->bootstrap;
There is an XS tutorial in the perl documentation, and reference documentation in perlxs.
XS is a good choice for modules, but is awkward for one-off scripts. The Inline::C module allows you to embed the glue C code directly into your Perl script and will take care of automatic compilation whenever the C code changes. However, less code can be generated automatically with this approach.

Function call if the second parameter is given null, the third parameter is giving as a second parameter?

I am a newbie in perl, I have defined a function
sub ex_arg($_)
{
print "$_[0]\n";
print "$_[1]\n";
print "$_[2]\n";
}
1;
in another page i am calling that page.
require "ex_arg.pl";
ex_arg(1,2,3);
ex_arg(1,,3); #in the second function i want the second parameter to be null
1;
is it possible to do this. am not getting the second parameter instead the third parameter is coming as the second parameter.
Am i doing something wrong. please correct me.
Thanks in advance.
The problem is that your argument list does not retain an empty value for the second argument before it is passed to the subroutine. The list 1,,3 will expand into the same list as 1,3.
You'll need to pass some value that actually exists, such as undef or the empty string.
ex_arg(1, undef, 3);
Then perhaps something like
sub ex_arg {
my ($arg1, $arg2, $arg3) = #_;
if (! defined($arg2)) { # checking if arg2 is empty
# do something
}
}
On a related note, you should not use prototypes in your subroutine declaration unless you know what it does. They are used to create specific behaviour in subroutines, and it has nothing to do with how other languages work, with regard to variables in the subroutine.
sub foo ( ... ) {
#^^^^^^^----- prototypes
sub foo { # this is the standard way to declare
Try this,
ex_arg(1, undef, 3);
ex_arg(1, , 3) for perl is same thing as ex_arg(1, 3)
perl -MO=Deparse -e 'ex_arg(1, , 3);'
ex_arg(1, 3); # <<<<<< deparsed
Side notes; if you don't want to use prototypes then sub ex_arg {..} is what you want.
Prefer my ($x,$y) = #_; over $_[0] and $_[1].

Returning c++ pointers to perl

I have a function in C++ such as:
void* getField(interface* p)
{
int* temp = new int( p->intValue);
cout<< "pointer value in c++" << temp << "value of temp = " << temp << endl;
return temp;
}
I am using SWIG to generate wrappers for the above class. Now I am trying to get the returned pointer value in Perl. How do i do it??
I have written the following perl script to call the function:
perl
use module;
$a = module::create_new_interface();
$b = module::getField();
print $b,"\n";
print $$b, "\n";
I ahve correctly defined the create_interface function since on calling the function getField() the correct intValue of the interface gets printed.
The output of the program is as follows:
_p_void=SCALAR(0x5271b0)
5970832
pointer value in c++ 0x5b1b90 value of temp 22
Why are the two values - the pointer in C++ and the reference in perl different? How do i get the intValue from the refernce? (i.e the value 22 )
Because you printed one in decimal and one in hexadecimal:
printf "pointer is 0x%x\n", $$b; # prints "pointer is 0x5b1b90"
Perl doesn't normally use pointers. The pack and unpack functions can deal with pointers (see Packing and Unpacking C Structures), but the normal Perl idiom would be to have the function return an integer instead of a pointer to an integer.

Perl: Can't pass an "on-the-fly" array to a sub

strftime(), as per cpan.org:
print strftime($template, #lt);
I just can't figure the right Perl code recipe for this one. It keeps reporting an error where I call strftime():
...
use Date::Format;
...
sub parse_date {
if ($_[0]) {
$_[0] =~ /(\d{4})/;
my $y = $1;
$_[0] =~ s/\d{4}//;
$_[0] =~ /(\d\d)\D(\d\d)/;
return [$2,$1,$y];
}
return [7,7,2010];
}
foreach my $groupnode ($groupnodes->get_nodelist) {
my $groupname = $xp->find('name/text()', $groupnode);
my $entrynodes = $xp->find('entry', $groupnode);
for my $entrynode ($entrynodes->get_nodelist) {
...
my $date_added = parse_date($xp->find('date_added/text()', $entrynode));
...
$groups{$groupname}{$entryname} = {...,'date_added'=>$date_added,...};
...
}
}
...
my $imday = $maxmonth <= 12 ? 0 : 1;
...
while (my ($groupname, $entries) = each %groups) {
...
while (my ($entryname, $details) = each %$entries) {
...
my $d = #{$details->{'date_added'}};
$writer->dataElement("creation", strftime($date_template, (0,0,12,#$d[0^$imday],#$d[1^$imday]-1,#$d[2],0,0,0)));
}
...
}
...
If I use () to pass the required array by strftime(), I get:
Type of arg 2 to Date::Format::strftime must be array (not list) at ./blah.pl line 87, near "))"
If I use [] to pass the required array, I get:
Type of arg 2 to Date::Format::strftime must be array (not anonymous list ([])) at ./blah.pl line 87, near "])"
How can I pass an array on the fly to a sub in Perl? This can easily be done with PHP, Python, JS, etc. But I just can't figure it with Perl.
EDIT: I reduced the code to these few lines, and I still got the exact same problem:
#!/usr/bin/perl
use warnings;
use strict;
use Date::Format;
my #d = [7,13,2010];
my $imday = 1;
print strftime( q"%Y-%m-%dT12:00:00", (0,0,12,$d[0^$imday],$d[1^$imday]-1,$d[2],0,0,0));
Where an array is required and you have an ad hoc list, you need to actually create an array. It doesn't need to be a separate variable, you can do just:
strftime(
$date_template,
#{ [0,0,12,$d[0^$imday],$d[1^$imday],$d[2],0,0,0] }
);
I have no clue why Date::Format would subject you to this hideousness and not just expect multiple scalar parameters; seems senseless (and contrary to how other modules implement strftime). Graham Barr usually designs better interfaces than this. Maybe it dates from when prototypes still seemed like a cool idea for general purposes.
To use a list as an anonymous array for, say, string interpolation, you could write
print "#{[1, 2, 3]}\n";
to get
1 2 3
The same technique provides a workaround to Date::Format::strftime's funky prototype:
print strftime(q"%Y-%m-%dT12:00:00",
#{[0,0,12,$d[0^$imday],$d[1^$imday]-1,$d[2],0,0,0]});
Output:
1900-24709920-00T12:00:00
Normally, it is easy to pass arrays "on-the-fly" to Perl subroutines. But Date::Format::strftime is a special case with a special prototype ($\#;$) that doesn't allow "list" arguments or "list assignment" arguments:
strftime($format, (0,0,12,13,7-1,2010-1900)); # not ok
strftime($format, #a=(0,0,12,13,7-1,2010-1900)); # not ok
The workaround is that you must call strftime with an array variable.
my #time = (0,0,12,13,7-1,2010-1900); # note: #array = ( ... ), not [ ... ]
strftime($format, #time);
I looked again and I see the real problem in this code:
my $d = #{$details->{'date_added'}};
$writer->dataElement("creation", strftime($date_template, (0,0,12,#$d[0^$imday],#$d[1^$imday]-1,#$d[2],0,0,0)));
Specifically #{$details->{'date_added'}} is a dereference. But you're assigning it to a scalar variable and you don't need to dereference in the line below it:
my #d = #{$details->{'date_added'}};
$writer->dataElement("creation", strftime($date_template, (0,0,12,$d[0^$imday],$d[1^$imday]-1,$d[2],0,0,0)));
I've created a regular array for your reference #d and just accessed it as a regular array ( $d[ ... ] instead of #$d[ ... ] )

In Perl, how can I unpack to several variables?

I have a struct wich contains:
struct mystruct{
int id[10];
char text[40];
unsigned short int len;
};
And I'm trying to unpack it in a single line, something like this:
my(#ids,$text,$length) = unpack("N10C40n",$buff) ;
But everything is going to the first array(#ids), i've tried templates as "N10 C40 n" and "(N10)(C40)(n)"
So, either this can't be done or I'm not using the proper template string.
Note: I'm using big endian data.
Any hints?
In list assignment the first array or hash will eat everything (how would it know where to stop?). Try this instead:
my #unpacked = unpack "N10Z40n", $buff;
my #ids = #unpacked[0 .. 9];
my ($text, $length) = #unpacked[10, 11];
you could also say
my #ids;
(#ids[0 .. 9], my ($text, $length)) = unpack "N10Z40n", $buff;
If the order of the #ids does not matter:
my ($length, $text, #ids) = reverse unpack("N10C40n",$buff) ;