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

📄 ch27.htm

📁 《Perl 5 Unreleased》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
However, this value will not be set unless the <TT><FONT FACE="Courier">OUTPUT</FONT></TT>

section with <TT><FONT FACE="Courier">RETVAL</FONT></TT> is defined.

You must have the two lines in a function to get it to return

a value:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">OUTPUT:<BR>

RETVAL</FONT></TT>

</BLOCKQUOTE>

<P>

You also have to remember to set <TT><FONT FACE="Courier">RETVAL</FONT></TT>

somewhere along the code to have a value to return. The type of

<TT><FONT FACE="Courier">RETVAL</FONT></TT> is the type of the

function you declared at the top. So, the <TT><FONT FACE="Courier">JulianDay</FONT></TT>

function has a <TT><FONT FACE="Courier">long</FONT></TT> <TT><FONT FACE="Courier">RETVAL</FONT></TT>,

whereas the <TT><FONT FACE="Courier">futureValue</FONT></TT> function

has a <TT><FONT FACE="Courier">double</FONT></TT> <TT><FONT FACE="Courier">RETVAL</FONT></TT>.

For return types of <TT><FONT FACE="Courier">void</FONT></TT>,

the <TT><FONT FACE="Courier">RETVAL</FONT></TT> variable is not

defined and you cannot use it.

<P>

Input parameters in an <TT><FONT FACE="Courier">XSUB</FONT></TT>

are normally initialized with their values from the values pushed

on the argument stack at the time of the call. Entries in the

<TT><FONT FACE="Courier">typemap</FONT></TT> file are used to

map the Perl values into their C counterparts in the <TT><FONT FACE="Courier">XSUB</FONT></TT>

function. You can use code that would be generated by the <TT><FONT FACE="Courier">xsubpp</FONT></TT>

compile directly to gain access to a variable. For example, in

the following function, the first argument is accessed via the

<TT><FONT FACE="Courier">SvPV</FONT></TT> map function:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">GetDayOfWeek(julianDay,dayOfWeek)<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long julianDay = (long)SvPV(ST(0),na)

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long dayOfWeek = 0</FONT></TT>

</BLOCKQUOTE>

<P>

In this example, <TT><FONT FACE="Courier">dayOfWeek</FONT></TT>

is assigned to a value of <TT><FONT FACE="Courier">0</FONT></TT>

as the default value. This is done so that if nothing is passed

in for <TT><FONT FACE="Courier">dayOfWeek</FONT></TT>, then it

will be set to <TT><FONT FACE="Courier">0</FONT></TT>. Defensive

programming like this makes the package easier to use.

<P>

You can even place assignments in the parameter list, like this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">DayOfWeek(julianDay,dayOfWeek = 0)<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long julianDay = (long)SvPV(ST(0),na)

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long dayOfWeek</FONT></TT>

</BLOCKQUOTE>

<P>

The default values set in the parameters may only be a number

or a string, not pointers. Also, you can define such values from

a right-to-left order in the parameter list. Thus, the following

line would cause unspeakable errors from <TT><FONT FACE="Courier">xsubpp</FONT></TT>:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">DayOfWeek(dayOfWeek = 0, julianDay)</FONT></TT>

</BLOCKQUOTE>

<P>

To allow the <TT><FONT FACE="Courier">XSUB</FONT></TT> for <TT><FONT FACE="Courier">DayOfWeek()</FONT></TT>

to have a default <TT><FONT FACE="Courier">date</FONT></TT> value,

you could rearrange the parameters to the <TT><FONT FACE="Courier">XSUB</FONT></TT>.

A Perl program will then be able to call <TT><FONT FACE="Courier">DayOfWeek()</FONT></TT>

with either of the following statements:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$status = DayOfWeek( $julianDay );<BR>

$status = DayOfWeek( );&nbsp;&nbsp;&nbsp;# Force it default to

jday of 0</FONT></TT>

</BLOCKQUOTE>

<P>

The code in the <TT><FONT FACE="Courier">Julian.xs</FONT></TT>

file would look like the following:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">int<BR>

DayOfWeek(jday = 0)<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long jday;<BR>

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CODE:<BR>

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (jday == 0) {<BR>

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

= 0;<BR>

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

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{

<BR>

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

= (jday % 7);<BR>

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

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OUTPUT:<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETVAL</FONT></TT>

</BLOCKQUOTE>

<P>

The <TT><FONT FACE="Courier">XSUB</FONT></TT> code generated for

this segment of code would look this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">XS(XS_Julian_DayOfWeek)<BR>

{<BR>

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

&nbsp;&nbsp;&nbsp;&nbsp;if (items &lt; 0 || items &gt; 1)<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;croak(&quot;Usage: Julian::DayOfWeek(jday

= 0)&quot;);<BR>

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

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long jday;<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;RETVAL;<BR>

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (items &lt; 1)<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jday = 0;

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else {<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jday = (long)SvIV(ST(0));

<BR>

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

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (jday == 0) {<BR>

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

= 0;<BR>

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

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETVAL = (jday % 7);<BR>

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

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ST(0) = sv_newmortal();<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sv_setiv(ST(0), (IV)RETVAL);<BR>

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

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

}</FONT></TT>

</BLOCKQUOTE>

<P>

In this code fragment, the special variable <TT><FONT FACE="Courier">items</FONT></TT>

tells the routine how many parameters have been passed into the

function. The <TT><FONT FACE="Courier">items</FONT></TT> variable

is tested to see how to initialize <TT><FONT FACE="Courier">jday</FONT></TT>

in this example. The <TT><FONT FACE="Courier">sv_newmortal()</FONT></TT>

function is used to clear out the return values for this <TT><FONT FACE="Courier">XSUB</FONT></TT>

function.

<P>

The use of ellipses (<TT><FONT FACE="Courier">...</FONT></TT>)

for passing variable-length argument lists is also supported in

<TT><FONT FACE="Courier">XSUB</FONT></TT>s. Your function can

easily get the number of arguments passed into it by looking at

the special <TT><FONT FACE="Courier">items</FONT></TT> variable.

The <TT><FONT FACE="Courier">items</FONT></TT> keyword is a reserved

variable and the <TT><FONT FACE="Courier">xsubpp</FONT></TT> compiler

supplies <TT><FONT FACE="Courier">items</FONT></TT> for all <TT><FONT FACE="Courier">XSUB</FONT></TT>s.

Using the <TT><FONT FACE="Courier">items</FONT></TT> variable

lets you accept an unknown number of arguments in your <TT><FONT FACE="Courier">XSUB</FONT></TT>

function.

<H2><A NAME="Keywords"><B><FONT SIZE=5 COLOR=#FF0000>Keywords</FONT></B></A>

</H2>

<P>

There are several special keywords in the <TT><FONT FACE="Courier">.xs</FONT></TT>

file that can also be used when writing extensions.

<H3><A NAME="TheMODULEKeyword"><B>The </B><TT><B><FONT SIZE=4 FACE="Courier">MODULE</FONT></B></TT><B><FONT SIZE=4>

Keyword</FONT></B></A></H3>

<P>

The <TT><FONT FACE="Courier">MODULE</FONT></TT> keyword is used

to start the XS code and to specify the name of the package currently

being defined. There is only one <TT><FONT FACE="Courier">MODULE</FONT></TT>

keyword per <TT><FONT FACE="Courier">.xs</FONT></TT> file. All

text before the <TT><FONT FACE="Courier">MODULE</FONT></TT> keyword

is not processed in any way by <TT><FONT FACE="Courier">xsubpp</FONT></TT>.

Do not modify the code before the <TT><FONT FACE="Courier">MODULE</FONT></TT>

keyword. If you have to add code, it will be passed through to

the final C file.

<P>

Here's the syntax for the <TT><FONT FACE="Courier">MODULE</FONT></TT>

keyword:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">MODULE packageName</FONT></TT>

</BLOCKQUOTE>

<P>

The <TT><FONT FACE="Courier">packageName</FONT></TT> is used as

the name of the <TT><FONT FACE="Courier">bootstrap</FONT></TT>

function for this module extension. The <TT><FONT FACE="Courier">MODULE</FONT></TT>

keyword is generated for you by <TT><FONT FACE="Courier">xsubpp</FONT></TT>.

<H3><A NAME="ThePACKAGEKeyword"><B>The </B><TT><B><FONT SIZE=4 FACE="Courier">PACKAGE</FONT></B></TT><B><FONT SIZE=4>

Keyword</FONT></B></A></H3>

<P>

On occasion, you may have more than one package per module. In

this case, the <TT><FONT FACE="Courier">PACKAGE</FONT></TT> keyword

is used to indicate which package within the module contains the

code that follows. Generally, the name following the <TT><FONT FACE="Courier">PACKAGE</FONT></TT>

keyword is the same as that following the <TT><FONT FACE="Courier">MODULE</FONT></TT>

keyword.

<P>

The <TT><FONT FACE="Courier">PACKAGE</FONT></TT> keyword is used

with the <TT><FONT FACE="Courier">MODULE</FONT></TT> keyword and

must follow on the same line as the <TT><FONT FACE="Courier">MODULE</FONT></TT>

keyword. You have to edit the <TT><FONT FACE="Courier">.xs</FONT></TT>

file yourself to make sure which package gets which function.

<H3><A NAME="TheCODEKeyword"><B>The </B><TT><B><FONT SIZE=4 FACE="Courier">CODE:</FONT></B></TT><B><FONT SIZE=4>

Keyword</FONT></B></A></H3>

<P>

The <TT><FONT FACE="Courier">CODE:</FONT></TT> keyword is used

to indicate where the real C code for a function begins. Use just

C code until you start a new block with another keyword, such

as <TT><FONT FACE="Courier">OUTPUT:</FONT></TT>. You can use C

comments (<TT><FONT FACE="Courier">/*...*/</FONT></TT>), ampersands,

and so on, and they will not be touched by the <TT><FONT FACE="Courier">xsubpp</FONT></TT>

compiler.

<P>

<TT><FONT FACE="Courier">xsubpp</FONT></TT> matches certain C

preprocessor directives that are allowed within the <TT><FONT FACE="Courier">CODE:</FONT></TT>

block. It also matches <TT><FONT FACE="Courier">#</FONT></TT>

used for Perl comments. The compiler passes the preprocessor directives

that it recognizes through to the final C file untouched and will

remove the commented lines. Comments can be added to <TT><FONT FACE="Courier">XSUB</FONT></TT>s

by placing <TT><FONT FACE="Courier">#</FONT></TT> at the beginning

of the line, too. Nested comments are not supported.

<P>

Be careful not to make the comment look like a C preprocessor

directive! The <TT><FONT FACE="Courier">xsubpp</FONT></TT> compiler

could be confused if a Perl comment begins to look like a C preprocessor

directive. The following is a bad idea:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">#define a variable</FONT></TT>

</BLOCKQUOTE>

<P>

Is the above line a comment or a C statement? I do not know how

this will be interpreted.

<P>

If you are going to mess with the argument stack, though, you'll

want to use the <TT><FONT FACE="Courier">PpcODE</FONT></TT> keyword,

which will be discussed later in the chapter.

<H3><A NAME="TheOUTPUTKeyword"><B>The </B><TT><B><FONT SIZE=4 FACE="Courier">OUTPUT:</FONT></B></TT><B><FONT SIZE=4>

Keyword</FONT></B></A></H3>

<P>

The <TT><FONT FACE="Courier">OUTPUT:</FONT></TT> keyword specifies

the return values from a function. You have seen it used earlier

in the case of the <TT><FONT FACE="Courier">RETVAL</FONT></TT>

assignment as a return. The <TT><FONT FACE="Courier">OUTPUT:</FONT></TT>

keyword generates code that does the mapping of the <TT><FONT FACE="Courier">XSUB</FONT></TT>

function's variables back to those in the Perl program calling

<TT><FONT FACE="Courier">XSUB</FONT></TT>. This keyword is used

after the code in the <TT><FONT FACE="Courier">CODE:</FONT></TT>

area. The <TT><FONT FACE="Courier">RETVAL</FONT></TT> variable

is not the default return variable in the <TT><FONT FACE="Courier">CODE:</FONT></TT>

area. Only by specifying it after the <TT><FONT FACE="Courier">OUTPUT:</FONT></TT>

keyword are you letting <TT><FONT FACE="Courier">xsubpp</FONT></TT>

know that it's a return variable for this function.

<P>

The <TT><FONT FACE="Courier">OUTPUT:</FONT></TT> keyword also

lists the input parameters for use as output variables. This may

be necessary when a parameter has been modified within the function

and the programmer would like the update to be seen by Perl.

<P>

Say that you define a function, which returns the day of the week,

given an <TT><FONT FACE="Courier">isFriday()</FONT></TT> function

in the <TT><FONT FACE="Courier">Julian</FONT></TT> package. The

function returns <TT><FONT FACE="Courier">true</FONT></TT> (<TT><FONT FACE="Courier">1</FONT></TT>)

if the day is a Friday. The day of the week is returned in the

second parameter passed to the function. The function is shown

in the <TT><FONT FACE="Courier">Julian.xs</FONT></TT> file as

this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">int<BR>

IsFriday(jDay, dayOfWeek)<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long jDay<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int dayOfWeek = NO_INIT<BR>

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CODE:<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int

dw;<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dw

= (int)(jDay % 7);<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

(dw == 3) RETVAL = 1;<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else

RETVAL = 0;<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dayOfWeek

= dw;<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OUTPUT:<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dayOfWeek<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETVAL</FONT></TT>

</BLOCKQUOTE>

<P>

This example uses a <TT><FONT FACE="Courier">NO_INIT</FONT></TT>

keyword to show that the <TT><FONT FACE="Courier">dayOfWeek

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -