📄 ch27.htm
字号:
5 $m1 = 07;<BR>
6 $d1 = 21;<BR>
7 $d2 = 22;<BR>
8<BR>
9 $yr1 = 1996;<BR>
10 $yr2 = 1996;<BR>
11<BR>
12 $jd1 = &Julian::JulianDay($m1,$d1,$yr1);<BR>
13 $jd2 = &Julian::JulianDay($m1,$d2,$yr2);<BR>
14<BR>
15 print "Day 1: $jd1 \n";<BR>
16 print "Day 2: $jd2 \n";<BR>
17 print "Delta: ",$jd2 - $jd1, "\n" ;</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
Now that you've learned some of the ways to create and use C extensions,
here's how to put them all together. First of all, look at the
<TT><FONT FACE="Courier">Julian.c</FONT></TT> file in Listing
27.9, put together by the Perl script.
<P>
The function is called <TT><FONT FACE="Courier">XS</FONT></TT>,
and the arguments are specified via the <TT><FONT FACE="Courier">dXSARGS</FONT></TT>
keyword.
<HR>
<BLOCKQUOTE>
<B>Listing 27.9. The </B><TT><B><FONT FACE="Courier">Julian.c</FONT></B></TT><B>
file.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier"> 1 /*<BR>
2 * This file was generated automatically by
xsubpp version 1.923 from the<BR>
3 * contents of Julian.xs. Don't edit this file,
edit Julian.XS instead.<BR>
4 *<BR>
5 * ANY chANGES
MADE HERE WILL BE LOST!<BR>
6 *<BR>
7 */<BR>
8<BR>
9 #ifdef _ _cplusplus<BR>
10 extern "C" {<BR>
11 #endif<BR>
12 #include "EXTERN.h"<BR>
13 #include "perl.h"<BR>
14 #include "XSUB.h"<BR>
15 #ifdef _ _cplusplus<BR>
16 }<BR>
17 #endif<BR>
18<BR>
19 #include <math.h><BR>
20 XS(XS_Julian_JulianDay)<BR>
21 {<BR>
22 dXSARGS;<BR>
23 if (items != 3)<BR>
24 croak("Usage:
Julian::JulianDay(month, day, year)");<BR>
25 {<BR>
26 int month
= (int)SvIV(ST(0));<BR>
27 int day
= (int)SvIV(ST(1));<BR>
28 long year
= (long)SvIV(ST(2));<BR>
29 long RETVAL;
<BR>
30 long
jul;<BR>
23 double
t1, t2;<BR>
24 t1
= 7 * floor((year + floor(month * 9)/12)/4);<BR>
25 t2
= floor(275 * month / 9);<BR>
26 jul
= (long) (floor(367 * year - t1 + t2 + day + 1721013.5));<BR>
27 }
<BR>
28 RETVAL
= jul;<BR>
29 ST(0) = sv_newmortal();
<BR>
30 sv_setiv(ST(0),
(IV)RETVAL);<BR>
31 }<BR>
32 XSRETURN(1);<BR>
33 }<BR>
34<BR>
35 #ifdef _ _cplusplus<BR>
36 extern "C"<BR>
37 #endif<BR>
38 XS(boot_Julian)<BR>
39 {<BR>
40 dXSARGS;<BR>
41 char* file = _ _FILE_ _;
<BR>
42<BR>
43 newXS("Julian::JulianDay",
XS_Julian_JulianDay, file);<BR>
44 ST(0) = &sv_yes;<BR>
45 XSRETURN(1);<BR>
46 }</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
The meaning of keywords such as <TT><FONT FACE="Courier">newXS</FONT></TT>,
<TT><FONT FACE="Courier">SvIV</FONT></TT>, and so on in the output
C file are explained in <A HREF="ch25.htm" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/ch25.htm" >Chapter 25</A>, "Perl
Internal Files and Structures." However, for the moment,
concentrate on the compiler itself and how it expects input.
<H2><A NAME="InputandOutputParameterstoFunctions"><B><FONT SIZE=5 COLOR=#FF0000>Input
and Output Parameters to Functions</FONT></B></A></H2>
<P>
The functions compiled by the <TT><FONT FACE="Courier">xsubpp</FONT></TT>
compiler are referred to as <TT><FONT FACE="Courier">XSUB</FONT></TT>.
You specify the parameters that are passed into the <TT><FONT FACE="Courier">XSUB</FONT></TT>
just after you declare the function return value and name. The
list of parameters looks very C-like, but the lines must be indented
by a tab stop, and each line should not have an ending semicolon.
<P>
The list of output parameters occurs after the <TT><FONT FACE="Courier">OUTPUT:</FONT></TT>
directive. The default value returned is <TT><FONT FACE="Courier">RETVAL</FONT></TT>.
The use of <TT><FONT FACE="Courier">RETVAL</FONT></TT> tells Perl
that you want to send this value back as the return value of the
<TT><FONT FACE="Courier">XSUB</FONT></TT> function. You still
have set <TT><FONT FACE="Courier">RETVAL</FONT></TT> to something.
You can also specify which variables used in the <TT><FONT FACE="Courier">XSUB</FONT></TT>
function should be placed into the respective Perl variables that
are passed in.
<H3><A NAME="ThetypemapFile"><B>The </B><TT><B><FONT SIZE=4 FACE="Courier">typemap</FONT></B></TT><B><FONT SIZE=4>
File</FONT></B></A></H3>
<P>
The <TT><FONT FACE="Courier">xsubpp</FONT></TT> compiler uses
rules to convert from Perl's internal data types to C's data types.
These rules are stored in the <TT><FONT FACE="Courier">typemap</FONT></TT>
file. The rules in <TT><FONT FACE="Courier">typemap</FONT></TT>
contain mappings for converting <TT><FONT FACE="Courier">int</FONT></TT>s,
unsigned <TT><FONT FACE="Courier">int</FONT></TT>s, and so on
into Perl scalars. Arrays are mapped to <TT><FONT FACE="Courier">char**</FONT></TT>
or <TT><FONT FACE="Courier">void</FONT></TT> pointers, and so
on. The <TT><FONT FACE="Courier">typemap</FONT></TT> file with
all the mappings is located in the <TT><FONT FACE="Courier">ExtUtils</FONT></TT>
directory under the Perl installation.
<P>
The <TT><FONT FACE="Courier">typemap</FONT></TT> file is split
into three sections. The first section is a mapping of various
C data types into a tag value. The second section is for converting
input parameters to C, and the third is for outputting parameters
from C to Perl.
<P>
Take a look at Listing 27.9 again. Note the <TT><FONT FACE="Courier">SvIV</FONT></TT>
for the <TT><FONT FACE="Courier">month</FONT></TT> declaration.
Now look in the <TT><FONT FACE="Courier">typemap</FONT></TT> file
for the declaration of <TT><FONT FACE="Courier">int</FONT></TT>.
You'll see it defined as <TT><FONT FACE="Courier">T_IV</FONT></TT>.
Now go to the second <TT><FONT FACE="Courier">INPUT</FONT></TT>
part in the file to see how <TT><FONT FACE="Courier">T_IV</FONT></TT>
is mapped for input. You'll see the following lines, which map
the integer from the Perl variable:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">T_IV<BR>
$var = ($type)SvIV($arg);</FONT></TT>
</BLOCKQUOTE>
<P>
Similarly, in the <TT><FONT FACE="Courier">OUTPUT</FONT></TT>
section of the <TT><FONT FACE="Courier">typemap</FONT></TT> file,
you'll see the following lines to generate a returned value. This
fragment places an integer into the <TT><FONT FACE="Courier">ST</FONT></TT>
array (which is indexed from <TT><FONT FACE="Courier">0</FONT></TT>
on up for all the incoming and outgoing arguments of a function):
<BLOCKQUOTE>
<TT><FONT FACE="Courier">T_IV<BR>
sv_setif($arg, (IV)$var);<BR>
</FONT></TT>
</BLOCKQUOTE>
<P>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR VALIGN=TOP><TD ><B>Tip</B></TD></TR>
<TR VALIGN=TOP><TD >
<BLOCKQUOTE>
With C pointers, the asterisk indirection operator (<TT><FONT FACE="Courier">*</FONT></TT>) defines the type <TT><FONT FACE="Courier">foo</FONT></TT> pointer. When using the address of a variable, the ampersand (<TT><FONT FACE="Courier">&</FONT></TT>)
is considered part of the variable, and you should use a pointer type.
</BLOCKQUOTE>
</TD></TR>
</TABLE></CENTER>
<P>
<P>
If you forgot to create the <TT><FONT FACE="Courier">typemap</FONT></TT>
file, you might see output that looks like this:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">Error: 'const char *' not in typemap
in Julian.xs, line XXX</FONT></TT>
</BLOCKQUOTE>
<P>
This error means that you have used a C data type that <TT><FONT FACE="Courier">xsubpp</FONT></TT>
doesn't know how to convert between Perl and C. The solution is
to create a custom <TT><FONT FACE="Courier">typemap</FONT></TT>
file that tells <TT><FONT FACE="Courier">xsubpp</FONT></TT> how
to do the conversions.
<P>
You can define your own <TT><FONT FACE="Courier">typemap</FONT></TT>
entries if you find certain parameters in the file that you cannot
find in the existing <TT><FONT FACE="Courier">typemap</FONT></TT>
file. For example, the type <TT><FONT FACE="Courier">double</FONT></TT>
is understood by Perl, but not <TT><FONT FACE="Courier">double
*</FONT></TT>. In this case you have to make an entry in the <TT><FONT FACE="Courier">typemap</FONT></TT>
file to convert the pointer to <TT><FONT FACE="Courier">double</FONT></TT>
to something Perl will understand. Try a <TT><FONT FACE="Courier">void</FONT></TT>
pointer.
<H2><A NAME="ThebootstrapFunction"><B><FONT SIZE=5 COLOR=#FF0000>The
</FONT></B><TT><B><FONT SIZE=5 COLOR=#FF0000 FACE="Courier">bootstrap</FONT></B></TT><B><FONT SIZE=5 COLOR=#FF0000>
Function</FONT></B></A></H2>
<P>
All Perl extensions require a Perl module with a call to the <TT><FONT FACE="Courier">bootstrap</FONT></TT>
function, which loads the extension into Perl. The module's functions
are two-fold: Export all the extension's functions and global
references to variables to the Perl script using the extension,
and load the <TT><FONT FACE="Courier">XSUB</FONT></TT>s into Perl
using dynamic linking. Thus, you require two modules: the <TT><FONT FACE="Courier">Exporter</FONT></TT>
to export your functions and the <TT><FONT FACE="Courier">DynaLoader</FONT></TT>
for dynamic loading. See the following example for the <TT><FONT FACE="Courier">Julian</FONT></TT>
package:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">package Julian; #
my package<BR>
<BR>
require Exporter; # <--- so that I can export
functions<BR>
require DynaLoader; # <--- for loading extensions<BR>
<BR>
@ISA = qw(Exporter DynaLoader); #inherit functionality.<BR>
<BR>
@EXPORT = qw( JulianDay ); # to reduce use of Julian::
in scripts.<BR>
<BR>
bootstrap Julian; # Load the extension in to
Perl<BR>
1;</FONT></TT>
</BLOCKQUOTE>
<H2><A NAME="PassingArguments"><B><FONT SIZE=5 COLOR=#FF0000>Passing
Arguments</FONT></B></A></H2>
<P>
Parameters are passed into an <TT><FONT FACE="Courier">XSUB</FONT></TT>
function via an argument stack. The same stack is used to store
the <TT><FONT FACE="Courier">XSUB</FONT></TT>'s return value.
All Perl functions are stack oriented and use indexes in their
own stack to access their variables.
<P>
The stacks are organized bottom up and can be indexed using the
<TT><FONT FACE="Courier">ST<I>(index)</I></FONT></TT> macro. The
first position on that stack that belongs to the active function
is referred to as index 0 for that function. The positions on
the stack are referred to as <TT><FONT FACE="Courier">ST(0)</FONT></TT>
for the first item, <TT><FONT FACE="Courier">ST(1)</FONT></TT>
for the next, and so on. The incoming parameters and outgoing
return values for an <TT><FONT FACE="Courier">XSUB</FONT></TT>
are always position 0. Parameters are pushed left to right.<P>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR VALIGN=TOP><TD ><B>Caution</B></TD></TR>
<TR VALIGN=TOP><TD >
<BLOCKQUOTE>
<TT><FONT FACE="Courier">ST(x)</FONT></TT> is a macro. Be careful not to do something like this when using it: <TT><FONT FACE="Courier">ST(x++)</FONT></TT>. Depending on how the macro is defined, you may increment <TT><FONT FACE="Courier">x</FONT></TT>
more than once. It won't now, but it just might. Handle macros with care.
</BLOCKQUOTE>
</TD></TR>
</TABLE></CENTER>
<H2><A NAME="TheRETVALVariableandtheOUTPUTSecti"><B><FONT SIZE=5 COLOR=#FF0000>The
</FONT></B><TT><B><FONT SIZE=5 COLOR=#FF0000 FACE="Courier">RETVAL</FONT></B></TT><B><FONT SIZE=5 COLOR=#FF0000>
Variable and the </FONT></B><TT><B><FONT SIZE=5 COLOR=#FF0000 FACE="Courier">OUTPUT</FONT></B></TT><B><FONT SIZE=5 COLOR=#FF0000>
Section</FONT></B></A></H2>
<P>
The <TT><FONT FACE="Courier">OUTPUT</FONT></TT> section of the
<TT><FONT FACE="Courier">xs</FONT></TT> file is where you place
return values. The return value is always <TT><FONT FACE="Courier">ST(0)</FONT></TT>.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -