为什么在XSUB中的输出变量中包含SvSETMAGIC()?

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

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

我不确定为什么需要set魔法(以及为什么不需要RETVAL),以及为什么哈希和数组元素参数需要set魔法?
2个回答

6
所有Perl的数据结构都支持magic(不仅限于SV,尽管名字上这样标注),对于哈希和数组而言,这是tie机制或fieldhash 的基础,后者实现了哈希条目级别的弱引用类似物。
由于OUTPUT指令显示了C体中可能被修改的参数,且传入可能包含设置magic的变量,按照typemap设置值而不调用set handler可能会导致不一致行为。
use Scalar::Util qw(weaken);

my $foo;
my $ref = \$foo;
weaken($ref);

作为魔法的一个例子,weaken 减少了 $foo 的引用计数,并添加了指向 $ref 的魔法,以便在 $foo 被垃圾回收时清除它。
此外,它还向 $ref 添加了设置魔法,以拆除这个反向引用,否则当 $foo 被销毁时,$ref 将被清除,即使此时它不再指向 $foo
如果将 $ref 用作参数,则会在堆栈上对其进行别名处理(这就是为什么 $_[0] 可以赋值):
modifies_arguments($ref);

sub modifies_arguments {
    $_[0] = "blah"; # set magic is invoked to tear down the back referencing
} 

如果'modifies_arguments'是纯Perl,那么很容易看出这样做的适当性,但当然对于XSUBs也必须保持相同的正确性假设,这就是为什么使用'OUTPUT'来标记哪些参数的值将被设置为C级别参数变量在函数体末尾时所拥有的值,并触发设置的魔法。
这不适用于'RETVAL',因为那不是技术上的赋值,而是将一个新的SV推入堆栈,并且任何设置的魔法都将在函数返回后由赋值操作(如果有)处理。

谢谢您澄清这个问题!那么括号中引用的文本:“"needed for hash or array element parameters that must be created if they didn't exist"”呢?这是指什么?这是否意味着标量不适用于set魔法或其他内容? - Håkon Hægland
my @array; modifies_arguments($array[42]) 只有在实际修改时才会创建数组元素,比如自动创建。如果数组是神奇的,则这将涉及对数组本身设置魔法。然而,这仍然适用于标量,就像上面的 $ref 示例一样。 - nothingmuch

2
很简单。每当您分配给标量时,如果它与魔术相关联,您需要随后调用SvSETMAGIC()
分配给RETVAL并不会分配给Perl变量,因此调用SvSETMAGIC(RETVAL)(除非您实际修改了RETVAL)是错误的。如果返回值被分配给调用者中的另一个标量,则在分配之前将调用SvGETMAGIC,在分配之后将调用SvSETMAGIC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接