📄 ch26.htm
字号:
<H2><A NAME="UsingSCALARContext"><B><FONT SIZE=5 COLOR=#FF0000>Using
</FONT></B><TT><B><FONT SIZE=5 COLOR=#FF0000 FACE="Courier">SCALAR</FONT></B></TT><B><FONT SIZE=5 COLOR=#FF0000>
Context</FONT></B></A></H2>
<P>
Here is an example of how to call a Perl function that takes three
arguments and returns an integer. This is an example of using
a function in a scalar context because it returns a scalar value.
The code is shown in Listing 26.6.
<HR>
<BLOCKQUOTE>
<B>Listing 26.6. A function used in a scalar context.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier"> 1 /* How to call a Perl subroutine
from C */<BR>
2 #include <stdio.h><BR>
3 #include <EXTERN.h><BR>
4 #include <perl.h><BR>
5<BR>
6 static int getSeconds(int
s, int m, int h);<BR>
7 static PerlInterpreter *my_perl;
<BR>
8<BR>
9 int main(int argc, char **argv,
char **env)<BR>
10 {<BR>
11 my_perl
= perl_alloc();<BR>
12 perl_construct(my_perl);
<BR>
13<BR>
14 perl_parse(my_perl,
NULL, argc, argv, env);<BR>
15 getSeconds(10,30,4);
/* TIME = 10:30:04 AM */<BR>
16 perl_destruct(my_perl);
<BR>
17 perl_free(my_perl);
<BR>
18 }<BR>
19<BR>
20 static int getSeconds(int s, int
m, int h)<BR>
21 {<BR>
22 dSP ; /*
init stack pointer */<BR>
23 int count
; /* keep return value */<BR>
24 ENTER
; /* start
temporary area */<BR>
25 SAVETMPS;
<BR>
26 PUSHMARK(sp)
; /* push mark
for last argument. */<BR>
27 XPUSHs(sv_2mortal(newSViv(s)));
/* leftmost argument */<BR>
28 XPUSHs(sv_2mortal(newSViv(m)));
/* go from left to right */<BR>
29 XPUSHs(sv_2mortal(newSViv(h)));
/* rightmost argument */<BR>
30 PUTBACK
; /*
make stack pointer available */<BR>
31 count
= perl_call_pv("seconds", G_SCALAR); /* call */<BR>
32 SPAGAIN
; /* reset stack pointer
*/<BR>
33 if (count
!= 1) /* check return value */<BR>
34 croak("Whoa
Nelly! This is wrong\n") ;<BR>
35 printf
("The number of seconds so far = %f for %d:%d:%d\n",
<BR>
POPi,h,m,s) ;<BR>
36 PUTBACK
; /* put the popped value on stack again */<BR>
37 FREETMPS
; /* free up temporary variables (NOT count) */<BR>
38 LEAVE
; /* get out and clean up stack */<BR>
39 }</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
Lines 2 through 4 declare the mandatory headers. At line 7 we
declare the prototype for the function we are going to call. You
can declare the function here instead if you like. The call to
this function, <TT><FONT FACE="Courier">getSeconds</FONT></TT>,
is made at line 15. The function itself is declared static to
prevent unlikely confusion with any predefined functions in the
Perl libraries.
<P>
At line 22, the call to the <TT><FONT FACE="Courier">dSP</FONT></TT>
macro initializes the stack. At line 23, the <TT><FONT FACE="Courier">count</FONT></TT>
variable is declared to be a nontemporary variable on the stack.
The <TT><FONT FACE="Courier">ENTER</FONT></TT> and <TT><FONT FACE="Courier">SAVETMPS</FONT></TT>
macros at lines 24 and 25 start the temporary variable area. A
marker to this stack location is pushed on at line 26.
<P>
The <TT><FONT FACE="Courier">ENTER/SAVETMPS</FONT></TT> pair creates
the start of code for all temporary variables that will be destroyed
on the return from the C function. The <TT><FONT FACE="Courier">FREETMPS/LEAVE</FONT></TT>
pair will be used to clean up and destroy the space allocated
on the calling stack for these temporary variables.
<P>
Now the parameters to the Perl subroutine are pushed onto the
stack one at a time from the leftmost parameter to the rightmost
parameter. Remember this order because the Perl function expecting
these parameters will be declared as this:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">sub seconds {<BR>
my($h, $m, $s)
= @_ ;<BR>
my $t;<BR>
$t = $s + $m * 60 + $h * 3600;<BR>
return
$t<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
The stack pointer is made into a globally available value with
the <TT><FONT FACE="Courier">PUTBACK</FONT></TT> macro in line
30. The actual call to the subroutine is made in line 31 with
the <TT><FONT FACE="Courier">G_SCALAR</FONT></TT> flag. On return
from the subroutine, we have to reset the stack pointer with the
<TT><FONT FACE="Courier">SPAGAIN</FONT></TT> (stack pointer again)
macro. The count must be <TT><FONT FACE="Courier">1</FONT></TT>,
or else we have an error.
<P>
The returned value is in <TT><FONT FACE="Courier">POPi</FONT></TT>.
The called function returned an integer value. To get other types
of values, you can use one of the following macros:
<UL>
<LI><TT><FONT FACE="Courier">POPs</FONT></TT> for an <TT><FONT FACE="Courier">SV</FONT></TT>
<LI><TT><FONT FACE="Courier">POPp</FONT></TT> for a pointer (such
as a pointer to a string)
<LI><TT><FONT FACE="Courier">POPn</FONT></TT> for a double
<LI><TT><FONT FACE="Courier">POPi</FONT></TT> for an integer
<LI><TT><FONT FACE="Courier">POPl</FONT></TT> for a long
</UL>
<P>
The <TT><FONT FACE="Courier">PUTBACK</FONT></TT> macro is used
to reset the Perl stack back to a consistent state just before
exiting the function. The <TT><FONT FACE="Courier">POPi</FONT></TT>
macro call only updated the local copy of the stack pointer. We
have to set the global value on the stack, too. All parameters
pushed onto the stack must be bracketed by the <TT><FONT FACE="Courier">PUSHMARK</FONT></TT>
and <TT><FONT FACE="Courier">PUTBACK</FONT></TT> macros. These
macros count the number of parameters being pushed and hence let
Perl know how to size the <TT><FONT FACE="Courier">@_</FONT></TT>
array. The <TT><FONT FACE="Courier">PUSHMARK</FONT></TT> macro
tells Perl to mark the stack pointer and must be specified even
if you are using no parameters. The <TT><FONT FACE="Courier">PUTBACK</FONT></TT>
macro sets the global copy of the stack pointer to the value of
the local copy of the stack pointer.
<P>
Here's another example of how to use a returned string from a
function using the <TT><FONT FACE="Courier">POPp</FONT></TT> macro.
(See Listing 26.7.) Look at lines 23 through 25 to see how strings
and integers are pushed onto the stack with the <TT><FONT FACE="Courier">XPUSHs(sv_2mortal(newSVpv(str,offset)));</FONT></TT>
and <TT><FONT FACE="Courier">XPUSHs(sv_2mortal(newSViv(offset)));</FONT></TT>
functions. The returned value from the actual call to the Perl
function is retrieved with the <TT><FONT FACE="Courier">POPp</FONT></TT>
macro.
<HR>
<BLOCKQUOTE>
<B>Listing 26.7. Using a returned string value.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier"> 1 /* Using returned strings from
functions */<BR>
2 #include <stdio.h><BR>
3 #include <EXTERN.h><BR>
4 #include <perl.h><BR>
5<BR>
6 static int MySubString(char
*a, int offset, int len);<BR>
7 static PerlInterpreter *my_perl;
<BR>
8<BR>
9 int main(int argc, char **argv,
char **env)<BR>
10 {<BR>
11 my_perl
= perl_alloc();<BR>
12 perl_construct(my_perl);
<BR>
13 perl_parse(my_perl,
NULL, argc, argv, env);<BR>
14 MySubString("Kamran
Was Here",7,3); /* return 'Was' */<BR>
15 perl_destruct(my_perl);
<BR>
16 perl_free(my_perl);
<BR>
17 }<BR>
18<BR>
19 static int MySubString(char *a,
int offset, int len)<BR>
20 {<BR>
21 dSP ;
<BR>
22 PUSHMARK(sp)
;<BR>
23 XPUSHs(sv_2mortal(newSVpv(a,
0)));<BR>
24 XPUSHs(sv_2mortal(newSViv(offset)));
<BR>
25 XPUSHs(sv_2mortal(newSViv(len)));
<BR>
26 PUTBACK
;<BR>
27 perl_call_pv("Csubstr",
G_SCALAR);<BR>
28 SPAGAIN
;<BR>
29 printf
("The substring is %s\n",(char *)POPp) ;<BR>
30 PUTBACK
;<BR>
31 FREETMPS
;<BR>
32 LEAVE
;<BR>
33 }</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
The function <TT><FONT FACE="Courier">Csubstr</FONT></TT> calls
the Perl <TT><FONT FACE="Courier">substr()</FONT></TT> as shown
here:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">sub Csubstr {<BR>
my ($s,$o,$l) = @_;<BR>
return substr($s,$o,$l);<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
The value of the <TT><FONT FACE="Courier">substr()</FONT></TT>
function call is returned back from the subroutine call. It's
this returned value that is used in the C program.
<H2><A NAME="ReturningListsfromSubroutines"><B><FONT SIZE=5 COLOR=#FF0000>Returning
Lists from Subroutines</FONT></B></A></H2>
<P>
Many Perl functions return lists as their results. C programs
can retrieve these values as well. Here's a simple Perl function
that returns the ratio of two numbers. (See Listing 26.8.) The
C program to call this function is shown in Listing 26.9.
<HR>
<BLOCKQUOTE>
<B>Listing 26.8. Ratio of numbers in a Perl function.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier"> 1 sub GetRatio<BR>
2 {<BR>
3 my($a, $b) = @_ ;<BR>
4 my $c, $d;<BR>
5 if ($a == 0) { $c = 1; $d = 0; }<BR>
6 elsif ($b == 0) { $c = 0; $d = 1; }<BR>
7 else {<BR>
8 $c = $a/$b;<BR>
9 $d = $b/$a;
<BR>
10 } <BR>
11 ($c,$d);<BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -