【问题标题】:"Uninitialized value" false positive“未初始化值”误报
【发布时间】:2012-06-04 19:15:13
【问题描述】:

我认为 PERL(CentOS 内核 2.6.18-308.8.1.el5 上的 5.8.8)给了我一个误报的“未初始化变量”警告。我所有的搜索都出现了合法的未初始化值问题。也许我的也是,如果是这样的话,那么对正在发生的事情(以及如何正确地做我想做的事情)的解释会很棒。我还查看了许多关于 hex() 和正确的函数参数习语的参考资料,我认为我做的都是正确的。

我的脚本读取 2 个文本文件:一个包含 32 位硬件地址,另一个包含从该地址读回的 32 位数据。每个文件中的值总是 8 个十六进制数字长,并且两个文件都是 100% 匹配的(地址文件中的第 1 行对应于数据文件中的第 1 行)。当数据值为非零时,一切都很好,但当数据值为 0 时,我收到警告:

Use of uninitialized value in string eq at ../VMetro_Parser.pl line 248.
Use of uninitialized value in hex at ../VMetro_Parser.pl line 250.

相关代码:

sub ppReg_TX_Mode_Reg {
    my( $data ) = @_; # first arg should be the Data field
    my $ret = "\t";
    if( $data eq "00000000" ) { print "TX_Mode_Reg got 0 input\n"; } #LINE 248
    #croak( "data not defined!" ) unless defined $data;
    my( $hex ) = hex($data); #LINE 250

    $ret .= sprintf( "Clear INTs: %02X   ",         (($hex >> 25) & 0x7F) );

产生预期行为的输入:

Address: 90000004
Data: 00000004

PERL 脚本的输出:

90000004 00000004 ->  Wr TX00 Mode_Reg
    Clear INTs: 00

产生意外“未初始化值”警告的输入:

Address: 90000004
Data: 00000000

PERL 脚本的输出:

90000004 00000000 ->  Wr TX00 Mode_Reg
TX_Mode_Reg got 0 input
    Clear INTs: 00

很明显,它正在识别作为字符串“00000000”传入的参数,但它也认为它是 undef(如果我取消注释,就会触发 croak 行)。什么给了?

一个有趣的事情是,还有其他数据为 0 的实例,但没有引发任何警告。其他 0 数据由不同的函数处理,发生在引发警告的行之后,但处理相同(除了上面代码中明显的调试操作,只是因为警告而添加)。

例如

sub ppReg_RX_Master_Mode_Reg {
    my( $data ) = @_; # first arg should be the Data field
    my $ret = "\t";
    my( $hex ) = hex($data);

不抛出任何警告。

【问题讨论】:

  • 您声称的输出中没有任何警告?!?!
  • 语言名称是“Perl”。这不是首字母缩写词。
  • use Devel::Peek qw( Dump ); Dump($data);(在比较之前)可能具有指导意义。
  • 您应该使用Data::Dumper 检查您的输入。这是调试脚本的一种很好的方式,也是一个核心模块。 print Dumper $data 会让你确切地知道你的变量中有什么。此外,您的问题中没有足够的信息来做任何事情,只能猜测,所以我建议您尽可能设置一个独立的示例。
  • @TLP,Data::Dumper 不会让您知道“变量中的确切内容”。这就是我建议的 Devel::Peek。如果这是 Perl 中的错误,那么额外的细节会很重要。

标签: perl embedded


【解决方案1】:

这不太可能是 Perl 的问题。

请记住,警告会发送到 STDERR,而您的输出会发送到 STDOUT。两者不一定同步,因此您不能将警告与同一记录的输出联系起来。

使用printdie 代替croak 可能会有所帮助,以便以正确的顺序显示警告。

我建议你把你的子程序改成

sub ppReg_TX_Mode_Reg {
  my ($data) = @_;
  do { warn 'Undefined $data parameter'; return; } unless defined $data;

  . . .
}

这样代码就不会针对无效数据执行。

您的问题可能出在从文件记录中提取数据的代码中。您是否正确处理空行?如果您需要帮助,请显示这部分代码。

【讨论】:

  • 添加 $| = 1;(禁用 STDOUT 上的缓冲)也可以帮助解决此类问题。
【解决方案2】:

不出所料,问题出在我的代码上,而不是 Perl :) 我正在使用调度表来调用我的处理函数。 Dispatch Table 定义中的拼写错误导致在 Perl 处理表声明时调用该函数。

违规代码:

# 'Dispatch table' is a hash for functions
my %regPPFn = (
        TX_Version_Reg  =>  \&ppReg_TX_Version_Reg,
        TX_Mode_Reg =>  \&ppReg_TX_Mode_Reg,
        TX_Run_Reg  =>  \&ppReg_TX_Run_Reg,
        ...
        # Note: GCs are mostly TXs, so mostly call the TX fn()s
        GC_Version_Reg  =>  \&ppReg_TX_Version_Reg,
        GC_Mode_Reg =>  &ppReg_TX_Mode_Reg,
        GC_DMA =>   \&ppReg_GC_DMA,
        GC__Reg =>  \&ppReg_GC__Reg,
        "" => sub { print "Dispatch table NULL lookup\n" }
        ); # Array of pointers to register Pretty Print functions

您可以看到 *GC_Mode_Reg* 的函数引用在 & 号之前缺少反斜杠。

GC_Mode_Reg =>  &ppReg_TX_Mode_Reg,

应该是

GC_Mode_Reg =>  \&ppReg_TX_Mode_Reg,

使用 Data::Dumper 是让我走上正轨的重要第一步,它向我展示了我的函数在“可能被调用”之前被调用过一次。使用 $| = 1 也帮助我相信了输出文本的顺序;我原以为在我的打印语句之前出现的警告消息是由于缓冲造成的。

由于解决方案与最初的假设/问题标题相差甚远,请告诉我您是否以及如何认为我应该编辑此问题。我犹豫要不要改变它,因为遇到同样问题的其他人可能会和我一样在错误的地方寻找。

【讨论】:

    猜你喜欢
    • 2014-02-05
    • 2011-09-14
    • 1970-01-01
    • 2018-05-09
    • 1970-01-01
    • 1970-01-01
    • 2012-07-15
    • 1970-01-01
    • 2021-04-11
    相关资源
    最近更新 更多