如何在z
子对象内模拟XS
子行为?
package XS;
sub hello {
print "ARGS: >>@_<<\n";
my $lvl;
while( my @frame = caller( $lvl++ ) ) {
print ">>@frame[0..4]<<\n";
}
}
sub z {
&hello;
}
在我的
.xs
文件中,我有:void
call_perl() {
call_pv( "XS::hello", G_NOARGS );
}
void
test(...)
CODE:
call_perl();
但是调用
XS::test(1,2,3)
不会将任何参数传递给hello
。输出:
ARGS: >><<
>>main -e 1 XS::hello <<
在这里,我们可以看到由于
$hasargs
标志未设置G_NOARG
标志,但是为什么刷新了@_
?我错过了什么?UPD
似乎找到了答案的一半。
G_NOARGS标志
具有不为Perl子例程创建@_数组的效果。
调用
XSUB
时,不要为其创建框架(不记得在哪里描述了),也不要为其填充@_
(这间接地描述了here)XSUB使用宏ST(x)引用其堆栈参数
因此,更精确的问题将是:
如何将
XSUB
堆栈参数传播到PP
子例程?注意:我不能只使用:
call_pv( "XS::hello", 0 );
因为这是顺序PP子调用。当它返回
XSUB
时,堆栈参数将由XS::hello
子的返回值替换int count = call_pv( "XS::hello", 0 );
STAGAIN;
printf( "%s\n", SvPV_nolen( ST(0) ) );
因此,我提供了
G_NOARGS
标志,以便能够在调用XSUB
子程序后访问PP
堆栈参数 最佳答案
这是XSUB
完成方式的代码(注意:在此示例中,我不处理返回参数):
test(...)
CODE:
AV *defav_old = GvAV(PL_defgv); # Save current @_
AV *av = newAV(); # Create new array
av_extend(av, items -1);
AvREIFY_only(av);
AvFILLp(av) = items -1;
Copy(MARK+1, AvARRAY(av), items, SV*); # Fill array by elements from stack
GvAV(PL_defgv) = av; # point @_ to our new array
PUSHMARK(SP);
int count = call_pv( "XS::Utils::hello", G_VOID | G_NOARGS );
GvAV(PL_defgv) = defav_old; # Restore old @_