Perl 为什么encode会提高;在@“uquot;中使用未初始化的值;?
对于Perl v5.14.2(由Debian Wheezy提供),此代码:Perl 为什么encode会提高;在@“uquot;中使用未初始化的值;?,perl,Perl,对于Perl v5.14.2(由Debian Wheezy提供),此代码: use Encode qw(encode); no warnings "all"; sub test_encode { return Encode::encode("utf8", $_[0]); } my $a=undef; my $r=test_encode(substr($a,0,1)); 在$r中生成空字符串。我同意 在Perl 5.18.2(Ubuntu 14.04)中,它似乎产生以下输出: 在@in
use Encode qw(encode);
no warnings "all";
sub test_encode {
return Encode::encode("utf8", $_[0]);
}
my $a=undef;
my $r=test_encode(substr($a,0,1));
在$r
中生成空字符串。我同意
在Perl 5.18.2(Ubuntu 14.04)中,它似乎产生以下输出: 在@in列表赋值中使用未初始化的值 /usr/lib/perl/5.18/Encode.pm第147行 (即使在主范围中禁用了警告,显然这不是警告。编辑:根据答案,这肯定是警告): 该列表分配将在
Encode.pm
中:
146 sub encode($$;$) {
147 my ( $name, $string, $check ) = @_;
148 return undef unless defined $string;
149 $string .= ''; # stringify;
调整代码时,如果将unde
传递给encode
而不是$\u0]
,则不再抱怨。如果在临时变量中传递的是$\u0]
的副本,而不是$\u0]
,它也不会抱怨
我的问题是:在这些版本之间,Perl会有什么变化来解释新的行为?Perl在Encode.pm第147行的@
中到底看到了什么
附录:添加
Dump($u0])代码>从Devel::Peek
在test\u encode
开始时,它输出:
Perl 5.14.2:
SV = PVLV(0x23a2c10) at 0x2340998
REFCNT = 1
FLAGS = (GMG,SMG)
IV = 0
NV = 0
PV = 0
MAGIC = 0x235f950
MG_VIRTUAL = &PL_vtbl_substr
MG_TYPE = PERL_MAGIC_substr(x)
TYPE = x
TARGOFF = 0
TARGLEN = 0
TARG = 0x235e370
SV = PV(0x233ec20) at 0x235e370
REFCNT = 2
FLAGS = (PADMY,POK,pPOK)
PV = 0x23576b0 ""\0
CUR = 0
LEN = 16
SV=0x2340998处的PVLV(0x23a2c10)
REFCNT=1
标志=(GMG、SMG)
IV=0
NV=0
PV=0
MAGIC=0x235f950
MG_VIRTUAL=&PL_vtbl_substr
MG_TYPE=PERL_MAGIC_substr(x)
类型=x
TARGOFF=0
TARGLEN=0
TARG=0x235e370
SV=0x235e370处的PV(0x233ec20)
REFCNT=2
FLAGS=(PADMY、POK、pPOK)
PV=0x23576b0”“\0
CUR=0
LEN=16
Perl 5.18.2:
SV = PVLV(0x25c07c0) at 0x2546cb8
REFCNT = 1
FLAGS = (GMG,SMG)
IV = 0
NV = 0
PV = 0
MAGIC = 0x2567dd0
MG_VIRTUAL = &PL_vtbl_substr
MG_TYPE = PERL_MAGIC_substr(x)
TYPE = x
TARGOFF = 0
TARGLEN = 1
TARG = 0x256f328
FLAGS = 0
SV = NULL(0x0) at 0x256f328
REFCNT = 2
FLAGS = (PADMY)
SV=0x2546cb8处的PVLV(0x25c07c0)
REFCNT=1
标志=(GMG、SMG)
IV=0
NV=0
PV=0
MAGIC=0x2567dd0
MG_VIRTUAL=&PL_vtbl_substr
MG_TYPE=PERL_MAGIC_substr(x)
类型=x
TARGOFF=0
TARGLEN=1
TARG=0x256f328
标志=0
SV=0x256f328处的NULL(0x0)
REFCNT=2
FLAGS=(PADMY)
不知道该怎么想,但结尾的SV
部分差别很大,看起来像是空字符串与空字符串(0x0)。很有趣。如果你做了几乎相同的事情,但是:
my $a=undef;
my $b = substr($a,0,1);
my $r=test_encode($b);
它很好用
或:
所以我想我必须说-这与substr
和上下文的返回值有关
例如,@[0]
未定义-@
未定义
$ perl -we'
my $x;
my $y = substr($x, 0, 1); # Line 3
'
Use of uninitialized value $x in substr at -e line 3.
Encode
模块具有:
#
# $Id: Encode.pm,v 2.75 2015/06/30 09:57:15 dankogai Exp $
#
package Encode;
use strict;
use warnings;
这将覆盖您的no warnings
指令,但是隐藏这样的警告并不是真正需要的。但这已经有一段时间了:
2.18 2006/06/03 20:28:48
! bin/enc2xs
overhauled the -C option
- added ascii-ctrl', 'null', 'utf-8-strict' to core
- auto-generated Encode::ConfigLocal no longer use v-string for version
- now searches modules via File::Find so Encode/JP/Mobile is happy
! Byte/Byte.pm CN/CN.pm EBCDIC/EBCDIC.pm JP/JP.pm KR/KR.pm Symbol/Symbol.pm
use strict added; though all they do is load XS, it's
still better a practice
! *.pm
use warnings added to all of them for better practices' sake.
因此,我建议您在工作时使用旧版本的Encode 这是警告
substr
在其第一个参数未定义时发出警告
$ perl -we'
my $x;
my $y = substr($x, 0, 1); # Line 3
'
Use of uninitialized value $x in substr at -e line 3.
,则警告现在在实际执行子字符串操作时发生,而不是在调用substr
时发生。当substr
用作左值时,实际的子字符串操作将在获取a值或将其存储在返回的标量中时执行
$ perl -we'
my $x;
my $r = \substr($x, 0, 1);
my $y = $$r; # Line 4
'
Use of uninitialized value in scalar assignment at -e line 4.
然后执行子字符串操作以允许以下操作:
$ perl -wE'$_ = "abc"; substr($_, 0, 1) = "!!!"; say'
!!!bc
由于警告现在在子字符串操作完成时发生,因此由op in Encode的上下文决定警告是否可见
$ 5.14.2t/bin/perl -e'use warnings; my $r = \substr(my $x, 0, 1); no warnings; my $y = $$r;'
Use of uninitialized value in scalar assignment at -e line 1.
$ 5.14.2t/bin/perl -e'no warnings; my $r = \substr(my $x, 0, 1); use warnings; my $y = $$r;'
$ 5.22.0t/bin/perl -e'use warnings; my $r = \substr(my $x, 0, 1); no warnings; my $y = $$r;'
$ 5.22.0t/bin/perl -e'no warnings; my $r = \substr(my $x, 0, 1); use warnings; my $y = $$r;'
Use of uninitialized value in scalar assignment at -e line 1.
为什么警告开始发生在实际执行子字符串操作的位置,而不是调用substr
时?我猜,但可能是为了解决以下问题和类似问题:
$ perl -wE'
my $x = "def";
my $r = \substr($x, 0, 1);
$x = "abc";
say "<$$r>";
'
<a>
$ 5.14.2t/bin/perl -wE'
my $x;
my $r = \substr($x, 0, 1);
$x = "abc";
say "<$$r>";
'
Use of uninitialized value $x in substr at -e line 4.
<>
$ 5.22.0t/bin/perl -wE'
my $x;
my $r = \substr($x, 0, 1);
$x = "abc";
say "<$$r>";
'
<a>
你也可以强制严格化
$ perl -MO=Concise,-exec -e'1 for "".substr($_, 0, 1)' 2>&1 | grep substr
8 <@> substr[t2] sK/3
$perl-MO=简明,-exec-e'1 for”“.substr($\u0,1)'2>&1 | grep substr
8 substr[t2]sK/3
@toolic:但是5.14(喘息)中的Encode.pm有使用警告代码>其中只有sameold Encode.pm是$Id:Encode.pm,v2.42 2010/12/31 22:48:10 dankogai Exp
嗯,我将深入挖掘。我怀疑我们会发现这在perldelta
的某个地方。Re“@[0]
未定义-@
未定义”,这毫无意义;数组不能未定义,只能为空。未定义的是LvTARG($\u0])
。因此,考虑到substr的延迟计算,有没有一种简单的方法可以使警告静音?(一开始避免substr(undef,…)
。不使用使用警告代码>将使警告静音。。。但那不是你真正想要的。阅读我刚刚添加到底部的部分。琐事:返回可赋值的四个运算符:substr
,键
,vec
和$\array
。
$ perl -MO=Concise,-exec -e'1 for "".substr($_, 0, 1)' 2>&1 | grep substr
8 <@> substr[t2] sK/3