📄 ch27.htm
字号:
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>
long julianDay = (long)SvPV(ST(0),na)
<BR>
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>
long julianDay = (long)SvPV(ST(0),na)
<BR>
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( ); # 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>
long jday;<BR>
<BR>
CODE:<BR>
<BR>
if (jday == 0) {<BR>
RETVAL
= 0;<BR>
}<BR>
else {
<BR>
RETVAL
= (jday % 7);<BR>
}<BR>
<BR>
OUTPUT:<BR>
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>
dXSARGS;<BR>
if (items < 0 || items > 1)<BR>
croak("Usage: Julian::DayOfWeek(jday
= 0)");<BR>
{<BR>
long jday;<BR>
int RETVAL;<BR>
<BR>
if (items < 1)<BR>
jday = 0;
<BR>
else {<BR>
jday = (long)SvIV(ST(0));
<BR>
}<BR>
if (jday == 0) {<BR>
RETVAL
= 0;<BR>
}<BR>
else {
<BR>
RETVAL = (jday % 7);<BR>
}<BR>
<BR>
ST(0) = sv_newmortal();<BR>
sv_setiv(ST(0), (IV)RETVAL);<BR>
}<BR>
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>
long jDay<BR>
int dayOfWeek = NO_INIT<BR>
<BR>
CODE:<BR>
int
dw;<BR>
dw
= (int)(jDay % 7);<BR>
if
(dw == 3) RETVAL = 1;<BR>
else
RETVAL = 0;<BR>
dayOfWeek
= dw;<BR>
OUTPUT:<BR>
dayOfWeek<BR>
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 + -