内置插件的内联文档?

Mic*_*man 10 perl

我遇到了一种情况,我无法以直观的方式禁止警告,因为perl正在调用内置函数.例如

use strict;
use warnings;

{
    no warnings 'substr';      # no effect
    foo(substr('123', 4, 6));  # out of range but shouldn't emit a warning
}

sub foo {
    my $s = shift;  # warning reported here
    # do something
}
Run Code Online (Sandbox Code Playgroud)

运行此代码会导致

substr outside of string at c:\temp\foo.pl line 10.
Run Code Online (Sandbox Code Playgroud)

为了禁止警告,我必须移动no warnings 'substr'内部功能.

sub foo {
    no warnings 'substr'; # works here, but there's no call to substr
    my $s = shift;        # no warnings here
    # do something
}
Run Code Online (Sandbox Code Playgroud)

我可以看到substr通过传递代码来内联调用perl -MO=Terse

LISTOP (0x27dcaa8) leave [1]
    OP (0x27a402c) enter
    COP (0x27dcac8) nextstate
    BINOP (0x27dcb00) leaveloop
        LOOP (0x27dcb20) enterloop
        LISTOP (0x27dcb68) lineseq
            COP (0x27dcb88) nextstate
            UNOP (0x27dcbc0) entersub [5]          # entry point for foo
                UNOP (0x27dcbf4) null [148]
                    OP (0x27dcbdc) pushmark
                    LISTOP (0x27dcc48) substr [4]  # substr gets called here
                        OP (0x27dcc30) null [3]
                        SVOP (0x27dcc84) const [6] PV (0x2319944) "123"
                        SVOP (0x27dcc68) const [7] IV (0x2319904) 4
                        SVOP (0x27dcc14) const [8] IV (0x231944c) 6
                    UNOP (0x27dcca0) null [17]
                        PADOP (0x27dccf4) gv  GV (0x2318e5c) *foo
Run Code Online (Sandbox Code Playgroud)

这个优化器行为是否记录在何处?perlsub只提到内联函数的内联.鉴于警告是在错误的行上报告的,并且no warnings在调用电话的词汇范围内没有工作,我倾向于将此报告为错误,尽管我无法想到它是如何合理的固定,同时保留优化.

注意:在Perl 5.16.1下观察到此行为.

cho*_*oba 8

这是一个记录在案的行为(在perldiag中):

字符串之外的substr

(W substr),(F)您试图引用指向字符串外部的substr().也就是说,偏移的绝对值大于字符串的长度.请参阅perlfunc中的"substr".如果在左值上下文中使用substr(例如,作为赋值的左侧或作为子例程参数),则此警告是致命的.

强调我的.

将呼叫更改为

foo(my $o = substr('123', 4, 6));
Run Code Online (Sandbox Code Playgroud)

让警告消失.

移动no warnings到sub不会改变我的行为.你有什么Perl版本?(5.14.4).

我用来测试的代码:

#!/usr/bin/perl
use strict;
use warnings;

$| = 1;

print 1, foo(my $s1 = substr('abc', 4, 6));
print 2, bar(my $s2 = substr('def', 4, 6));

{
    no warnings 'substr';
    print 3, foo(my $s3 = substr('ghi', 4, 6));
    print 4, bar(my $s4 = substr('jkl', 4, 6));
    print 5, bar(substr('mno', 4, 6)); # Stops here, reports line 12.
    print 6, foo(substr('pqr', 4, 6));
}
print "ok\n";

sub foo {
    my $s = shift;
}

sub bar {
    no warnings 'substr';
    my $s = shift;
}
Run Code Online (Sandbox Code Playgroud)

更新:

我在5.10.1中得到了相同的行为,但在5.20.1中,行为如您所述.


ike*_*ami 5

正如你从B :: Terse看到的那样,substr没有内联.

$ perl -MO=Concise,-exec -e'f(substr($_, 3, 4))'
1  <0> enter
2  <;> nextstate(main 1 -e:1) v:{
3  <0> pushmark s
4  <#> gvsv[*_] s
5  <$> const[IV 3] s
6  <$> const[IV 4] s
7  <@> substr[t4] sKM/3        <-- The substr operator is evaluated first.
8  <#> gv[*f] s/EARLYCV
9  <1> entersub[t5] vKS/TARG   <-- The sub call second.
a  <@> leave[1 ref] vKP/REFC
-e syntax OK
Run Code Online (Sandbox Code Playgroud)

substr被称为左值上下文时,substr返回一个包含传递给的操作数的魔法标量substr.

$ perl -MDevel::Peek -e'$_ = "abcdef"; Dump(${\ substr($_, 3, 4) })'
SV = PVLV(0x2865d60) at 0x283fbd8
  REFCNT = 2
  FLAGS = (GMG,SMG)          <--- Gets and sets are magical.
  IV = 0                          GMG: A function that mods the scalar
  NV = 0                               is called before fetches.
  PV = 0                          SMG: A function is called after the
  MAGIC = 0x2856810                    scalar is modified.
    MG_VIRTUAL = &PL_vtbl_substr
    MG_TYPE = PERL_MAGIC_substr(x)
  TYPE = x
  TARGOFF = 3                      <--- substr's second arg
  TARGLEN = 4                      <--- substr's third arg
  TARG = 0x287bfd0                 <--- substr's first arg
  FLAGS = 0              
  SV = PV(0x28407f0) at 0x287bfd0  <--- A dump of substr's first arg
    REFCNT = 2
    FLAGS = (POK,IsCOW,pPOK)
    PV = 0x2865d20 "abcdef"\0
    CUR = 6
    LEN = 10
    COW_REFCNT = 1
Run Code Online (Sandbox Code Playgroud)

子程序参数在左值上下文中计算,因为子程序参数总是通过Perl [1]中的引用传递.

$ perl -E'sub f { $_[0] = "def"; }  $x = "abc"; f($x); say $x;'
def
Run Code Online (Sandbox Code Playgroud)

子字符串操作在访问魔法标量时发生.

$ perl -E'$x = "abc"; $r = \substr($x, 0, 1); $x = "def"; say $$r;'
d
Run Code Online (Sandbox Code Playgroud)

这样做是为了允许 substr(...) = "abc";


  1. 这可能是使用类似于以下语言记录的:"元素@_是子例程参数的别名."