【问题标题】:Why include SvSETMAGIC() on output variables in an XSUB?为什么在 XSUB 的输出变量中包含 SvSETMAGIC()?
【发布时间】:2016-12-15 21:42:27
【问题描述】:

看了perlxs documentation,我来到了OUTPUT关键字的部分:

xsubpp 为 XSUB 的 OUTPUT 部分,RETVAL 除外。这是通常想要的 行为,因为它负责在输出上正确调用“设置”魔法 参数(需要散列或数组元素参数,必须是 如果它们不存在则创建)。

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

【问题讨论】:

    标签: perl xs


    【解决方案1】:

    Perl 的所有数据结构都支持魔法,不仅仅是 SVs(尽管有名字),特别是对于哈希和数组,这是 tie 机制或 fieldhash 之类的东西的基础,它实现了一个类似的东西散列条目级别的弱引用。

    由于OUTPUT 指令指示了哪些参数可能会被 XSUB 的 C 主体修改,并且可能会传入包含 set magic 的变量,因此根据类型映射设置值而不调用 set 处理程序可能会导致不一致的行为。

    use Scalar::Util qw(weaken);
    
    my $foo;
    my $ref = \$foo;
    weaken($ref);
    

    作为魔术的示例,weaken 减少了 $foo 的引用计数,并添加了指向 $ref 的魔术,以便在 $foo 被垃圾回收时将其清除。

    此外,它还为$ref 添加了set magic,以拆除这个反向引用,否则当$foo 被销毁时,$ref 将被清除,即使此时它不再指向$foo

    如果你使用 $ref 作为参数,它会在堆栈上得到别名(这就是$_[0] is 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 魔法都将在函数返回后由赋值操作(如果有)处理。

    【讨论】:

    • 感谢您澄清这一点!括号中的引用文本是什么:"needed for hash or array element parameters that must be created if they didn't exist"?这是指什么?这是否意味着 set 魔法不适用于标量或其他东西?
    • my @array; modifies_arguments($array[42]) 只会在实际修改时创建数组元素,参见。自动复活。如果阵列是魔法的,那么这将涉及阵列本身的设置魔法。但是,这仍然适用于标量,如上面的 $ref 示例。
    【解决方案2】:

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

    分配给RETVAL 不会分配给Perl 变量,所以调用SvSETMAGIC(RETVAL)(除非你实际上修改了RETVAL)是错误的。如果返回的值被赋值给调用者中的另一个标量,那么赋值会在赋值前对返回的值调用SvGETMAGIC,在赋值后对已赋值的变量调用SvSETMAGIC

    【讨论】:

      猜你喜欢
      • 2019-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-17
      • 1970-01-01
      • 1970-01-01
      • 2019-07-28
      相关资源
      最近更新 更多