⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch27.htm

📁 《Perl 5 Unreleased》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
&nbsp;5 $m1 = 07;<BR>

&nbsp;6 $d1 = 21;<BR>

&nbsp;7 $d2 = 22;<BR>

&nbsp;8<BR>

&nbsp;9 $yr1 = 1996;<BR>

10 $yr2 = 1996;<BR>

11<BR>

12 $jd1 = &amp;Julian::JulianDay($m1,$d1,$yr1);<BR>

13 $jd2 = &amp;Julian::JulianDay($m1,$d2,$yr2);<BR>

14<BR>

15 print &quot;Day 1: $jd1 \n&quot;;<BR>

16 print &quot;Day 2: $jd2 \n&quot;;<BR>

17 print &quot;Delta: &quot;,$jd2 - $jd1, &quot;\n&quot; ;</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">&nbsp;1 /*<BR>

&nbsp;2&nbsp;&nbsp;* This file was generated automatically by

xsubpp version 1.923 from the<BR>

&nbsp;3&nbsp;&nbsp;* contents of Julian.xs. Don't edit this file,

edit Julian.XS instead.<BR>

&nbsp;4&nbsp;&nbsp;*<BR>

&nbsp;5&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ANY chANGES

MADE HERE WILL BE LOST!<BR>

&nbsp;6&nbsp;&nbsp;*<BR>

&nbsp;7&nbsp;&nbsp;*/<BR>

&nbsp;8<BR>

&nbsp;9 #ifdef _&nbsp;_cplusplus<BR>

10 extern &quot;C&quot; {<BR>

11 #endif<BR>

12 #include &quot;EXTERN.h&quot;<BR>

13 #include &quot;perl.h&quot;<BR>

14 #include &quot;XSUB.h&quot;<BR>

15 #ifdef _&nbsp;_cplusplus<BR>

16 }<BR>

17 #endif<BR>

18<BR>

19 #include &lt;math.h&gt;<BR>

20 XS(XS_Julian_JulianDay)<BR>

21 {<BR>

22&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dXSARGS;<BR>

23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (items != 3)<BR>

24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;croak(&quot;Usage:

Julian::JulianDay(month, day, year)&quot;);<BR>

25&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>

26&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;month

= (int)SvIV(ST(0));<BR>

27&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;day

= (int)SvIV(ST(1));<BR>

28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;&nbsp;&nbsp;year

= (long)SvIV(ST(2));<BR>

29&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;&nbsp;&nbsp;RETVAL;

<BR>

30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long

jul;<BR>

23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;double

t1, t2;<BR>

24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t1

= 7 * floor((year + floor(month * 9)/12)/4);<BR>

25&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t2

= floor(275 * month / 9);<BR>

26&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jul

= (long) (floor(367 * year - t1 + t2 + day + 1721013.5));<BR>

27&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

<BR>

28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETVAL

= jul;<BR>

29&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ST(0) = sv_newmortal();

<BR>

30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sv_setiv(ST(0),

(IV)RETVAL);<BR>

31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XSRETURN(1);<BR>

33 }<BR>

34<BR>

35 #ifdef _&nbsp;_cplusplus<BR>

36 extern &quot;C&quot;<BR>

37 #endif<BR>

38 XS(boot_Julian)<BR>

39 {<BR>

40&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dXSARGS;<BR>

41&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char* file = _&nbsp;_FILE_&nbsp;_;

<BR>

42<BR>

43&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newXS(&quot;Julian::JulianDay&quot;,

XS_Julian_JulianDay, file);<BR>

44&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ST(0) = &amp;sv_yes;<BR>

45&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;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>, &quot;Perl

Internal Files and Structures.&quot; 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>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$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>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;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">&amp;</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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

my package<BR>

<BR>

require Exporter;&nbsp;&nbsp;&nbsp;# &lt;--- so that I can export

functions<BR>

require DynaLoader; # &lt;--- for loading extensions<BR>

<BR>

@ISA = qw(Exporter DynaLoader); #inherit functionality.<BR>

<BR>

@EXPORT = qw( JulianDay );&nbsp;&nbsp;# to reduce use of Julian::

in scripts.<BR>

<BR>

bootstrap Julian;&nbsp;&nbsp;&nbsp;# 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 + -