How to treat a C language structure as a Perl object in XS
In XS, you can also treat the structure itself as a Perl object. I will explain how to treat a C language structure as a Perl object.
Create a module with h2xs
First, create a module for XS with h2xs.
h2xs -A -n SomeModule
This will create a directory called "SomeModule". The following files and directories will be created.
Changes lib/Makefile.PL MANIFEST ppport.h README SomeModule.xs t/</pre> <h3>XS file description</h3> Let's write an XS file. The pointer of the structure is converted to size_t type by PTR2INT. In addition, size_t type is converted to SV * type, SV * type is converted to SV * type reference, and finally bless is converted to object. The size_t type is an integer type, but the address value should be received as the size_t type. When retrieving, dereference is performed, the value of IV contained in SV * is fetched, and INT2PTR is converted into a pointer to the structure. <pre> # include "EXTERN.h" # include "perl.h" # include "XSUB.h" # include "ppport.h" typedef struct { double x; double y; } Point; MODULE = Point PACKAGE = Point void new(...) PPCODE: { // name of the class char * class_name = SvPV_nolen (ST (0)); // x and y double x = SvNV (ST (1)); double y = SvNV (ST (2)); // Create structure (create as pointer) Point * point = (Point *) malloc (sizeof (Point)); point->x = x; point->y = y; // Convert pointer to size_t type size_t point_iv = PTR2IV (point); // Convert size_t type to SV * type SV * point_sv = sv_2mortal (newSViv (point_iv)); // Create SV * type reference SV * point_svrv = sv_2mortal (newRV_inc (point_sv)); // create an object SV * point_obj = sv_bless(point_svrv, gv_stashpv (class_name, 1)); XPUSHs (point_obj); XSRETURN (1); } void x (...) PPCODE: { // get the object SV * point_obj = ST (0); // Dereference SV * point_sv = SvROK (point_obj)? SvRV (point_obj): point_obj; // Convert SV * type to size_t type size_t point_iv = SvIV (point_sv); // Convert size_t type to pointer Point * point = INT2PTR (Point *, point_iv); // get x double x = point->x; // Convert x to SV * type SV * x_sv = sv_2mortal (newSVnv (x)); XPUSHs (x_sv); XSRETURN (1); } void y (...) PPCODE: { // get the object SV * point_obj = ST (0); // Dereference SV * point_sv = SvROK (point_obj)? SvRV (point_obj): point_obj; // Convert SV * type to size_t type size_t point_iv = SvIV (point_sv); // Convert size_t type to pointer Point * point = INT2PTR (Point *, point_iv); // get x double y = point->y; // Convert x to SV * type SV * y_sv = sv_2mortal (newSVnv (y)); XPUSHs (y_sv); XSRETURN (1); } void DESTORY (...) PPCODE: { // get the object SV * point_obj = ST (0); // Dereference SV * point_sv = SvROK (point_obj)? SvRV (point_obj): point_obj; // Convert SV * type to size_t type size_t point_iv = SvIV (point_sv); // Convert size_t type to pointer Point * point = INT2PTR (Point *, point_iv); // Release Point * free (point); XSRETURN (0); } MODULE = SomeModule PACKAGE = SomeModule
Creating a Point module
Please put a file called Point.pm under lib. SomeModule is loaded because SomeModule has a binding description.
package Point; use SomeModule; 1;
Test script
Create a test script. This should be in the same directory where the XS files are located.
use strict; use warnings; use Point; my $point = Point->new(1, 2); print $point->x . "\n"; print $point->y . "\n";
Compile and run
Let's compile and run it.
perl Makefile.PL make perl -Mblib test.pl
If the output is as follows, it is successful.
1 2