9

阅读perlxs 文档,我来到了关于OUTPUT关键字的部分:

xsubpp为 XSUB 的 OUTPUT 部分中的所有参数发出自动SvSETMAGIC(),除了 RETVAL。这是通常需要的行为,因为它负责在输出参数上正确调用“设置”魔法(如果哈希或数组元素参数不存在,则必须创建它们)。

我不确定我是否理解为什么需要set魔法(以及为什么不需要魔法RETVAL)?为什么set哈希和数组元素参数需要魔法?

4

2 回答 2

6

Perl 的所有数据结构都支持魔法,不仅仅是SVs(尽管有名字),特别是对于哈希和数组,这是类似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 魔术都将在函数返回后由赋值操作(如果有)处理。

于 2016-12-15T23:05:13.630 回答
2

这很简单。每当你分配给一个标量时,你需要SvSETMAGIC()在之后调用它,以防它有与之关联的魔法。

分配 toRETVAL不会分配给 Perl 变量,因此调用SvSETMAGIC(RETVAL)(除非您实际上已修改RETVAL)是错误的。如果返回的值被分配给调用者中的另一个标量,则赋值将在赋值之前调用SvGETMAGIC返回的值,并SvSETMAGIC在赋值之后调用已分配的变量。

于 2016-12-16T00:54:08.190 回答