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.
Related
I am using a Perl script.
I want to use 32 byte signed integer form like c language.
For example, if I add 1 to the integer value, I want to output it as shown below.
my $val = 0;
while(1){
print $val++;
}
-------------------------------
The desired result.
0
1
2
.
.
.
2,147,483,646
2,147,483,647
-2,147,483,648
-2,147,483,647
-2,147,483,647
.
.
.
But I do not know how to use 4byte signed integer value.
You can't tell Perl what size of integers you want to use.[1]
But that doesn't appear to be what you want. You appear to want a counter that wraps from 2,147,483,647 to -2,147,483,648.
You'll have to do it the same way as you would in C:
int32_t i = 0;
...
/* Can't use use ++i because incrementing 2147483647 is undefined behaviour */
i = i == 2147483647 ? -2147483648 : i+1;
or
int32_t i = 0;
...
/* Can't use use ++i because incrementing 2147483647 is undefined behaviour */
i = (int32_t)((((int64_t)i)+1) & 0xFFFFFFFF);
Perl uses three numerical storage types:
signed integer of size ivsize
unsigned integer of size uvsize
floating-point number of size nvsize
You can get The size of each of type (in bytes) as follows:
perl -le'use Config qw( %Config ); print $Config{ivsize};'
perl -le'use Config qw( %Config ); print $Config{uvsize};'
perl -le'use Config qw( %Config ); print $Config{nvsize};'
or
perl -V:ivsize
perl -V:uvsize
perl -V:nvsize
Not only is the size of these types fixed when perl is compiled, you can't select which of these types perl will use to store a value. Furthermore, perl will automatically convert from one type to another when an overflow would occur. (Example)
You can achieve this by using pack/unpack. Pack your variable into an unsigned int, then unpack it to a signed int.
my $val = 2147483646;
for(my $i=0;$i<4;$i++){
my $uint = pack('I', $val++);
print unpack('i', $uint);
}
Note, that:
(This 'integer' is _at_least_ 32 bits wide. Its exact
size depends on what a local C compiler calls 'int'.)
so it might be better to use N or V instead of I.
ideone demo
With this script
use warnings;
use strict;
my $w = rand * 4;
the interpreter gives me this warning: Argument "*main::4" isn't numeric in rand. I don't understand why this is and would like someone to explain what's happening here.
Of course, I can make the warning disappear with rand() * 4 or 4 * rand.
In perl, * is the sigil for a weird type called a typeglob. A typeglob is the symbol table entry for all objects identified by that name - for example, if you were to run:
$a = 1;
*b = *a;
print $b;
You would get 1. There are some other things you can do with typeglobs, but none of them are terribly useful or relevant.
The Perl parser is working left to right. It sees that you are attempting to assign the value of rand * 4 to my $w. It identifies rand as the name of a built-in function, and starts looking for an argument. Then, it sees a *, and interprets it as a sigil rather than an operator. It successfully identifies the argument (*4) which is syntactically a legal identifier, and as far as the interpreter is concerned, it's finished parsing that line. It isn't until we actually call the built-in rand that the interpreter figures out that a typeglob isn't a legal argument.
So, this happens because:
Perl checks to see if rand has a legal argument first, and if it doesn't, it calls it with no argument
In Perl, *4 is the legal name of a variable
Perl does not have strict types on arguments, so the lexer can't recognize that rand doesn't want to have a typeglob passed in to it
You can fix this by:
Reordering the arguments 4 * rand
Explicitly calling rand() with no arguments
Perl was interpreting *4 as argument to rand(), and to be more precise as *main::4 which is globtype to package variable.
perl -we 'my $w = rand (*::4);'
same output:
Argument "*main::4" isn't numeric in rand
Deparse has same idea about these equivalents,
perl -MO=Deparse -e 'my $w = rand *4;'
my $w = rand *4;
perl -MO=Deparse -e 'my $w = rand *main::4;'
my $w = rand *4;
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.
I have a perl script generator.pl that defines some routines like:
sub a($) {
...
print FILE "$_[0]";
...
}
...
sub b($$) {
...
print FILE "$_[0], $_[1]";
...
}
...
$subsfile = $ARGV[0] . "/subs.pl";
$generatedfile = $ARGV[0] . "/generated.file";
open FILE, '>>', "$generatedfile" or die "error trying to append: $!";
do "$subsfile";
close FILE;
Let's assume that, for example subs.pl is like this:
a(1);
a(x);
b(1-2, z);
b(1-x, i);
b(y-z, j);
I call generator script in this way:
C:\Users\Me>perl generator.pl "D:/another/path"
Result is that D:/another/path/generated.file is created but it contains 0 bytes. Printing "print $#;" after do statement, I'm obtaining:
Transliteration pattern not terminated at...
If I try to call the script with a subs.pl having each actual argument double quoted
a("1");
a("x");
b("1-2", "z");
b("1-x", "i");
...
it works.
How can I do to make things work without using double quotes?
tr/// is transliteration operator which can be also written as y///. Further, it can be modified to take another character as delimiter, ie. y---.
So when perl see something like,
b(y-z, j);
it expects
b(y-z, j--);
which is correct and would in example above count all occurrences of z, ,, , and j chars in default variable $_, and pass it as argument to b().
Since compiler expectations are not met, it throws:
Transliteration pattern not terminated at...
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);
}