阅读perlxs 文档,我来到了关于OUTPUT
关键字的部分:
xsubpp为 XSUB 的 OUTPUT 部分中的所有参数发出自动
SvSETMAGIC()
,除了 RETVAL。这是通常需要的行为,因为它负责在输出参数上正确调用“设置”魔法(如果哈希或数组元素参数不存在,则必须创建它们)。
我不确定我是否理解为什么需要set
魔法(以及为什么不需要魔法RETVAL
)?为什么set
哈希和数组元素参数需要魔法?
Perl 的所有数据结构都支持魔法,不仅仅是SV
s(尽管有名字),特别是对于哈希和数组,这是类似tie
机制或类似fieldhash
在哈希条目级别实现弱引用的类似事物的基础。
由于该OUTPUT
指令指示了哪些参数可能会被 XSUB 的 C 主体修改,并且可能会传入包含 set magic 的变量,因此根据 typemap 设置值而不调用 set 处理程序可能会导致不一致的行为。
use Scalar::Util qw(weaken);
my $foo;
my $ref = \$foo;
weaken($ref);
作为魔术的一个例子,weaken
减少 的引用计数$foo
,并添加魔术指向,以便在垃圾收集$ref
时将其清除。$foo
此外,它还为 , 添加了 set 魔法$ref
,以拆除这个反向引用,否则当$foo
被销毁时,$ref
即使此时它不再指向 ,也会被清除$foo
。
如果您使用 $ref 作为参数,它会在堆栈上得到别名(这就是$_[0]
assignable的原因):
modifies_arguments($ref);
sub modifies_arguments {
$_[0] = "blah"; # set magic is invoked to tear down the back referencing
}
如果modifies_arguments
是纯 Perl,很容易看出为什么这是合适的,但是关于正确性的相同假设当然必须适用于 XSUB,这就是为什么OUTPUT
用于标记哪些参数的值将设置为 C 级参数变量所具有的任何值的原因结束函数体,并设置魔法触发。
这不适用于RETVAL
,因为这在技术上不是一个赋值,而是将一个新的 SV 压入堆栈,并且任何 set 魔术都将在函数返回后由赋值操作(如果有)处理。
这很简单。每当你分配给一个标量时,你需要SvSETMAGIC()
在之后调用它,以防它有与之关联的魔法。
分配 toRETVAL
不会分配给 Perl 变量,因此调用SvSETMAGIC(RETVAL)
(除非您实际上已修改RETVAL
)是错误的。如果返回的值被分配给调用者中的另一个标量,则赋值将在赋值之前调用SvGETMAGIC
返回的值,并SvSETMAGIC
在赋值之后调用已分配的变量。