首页 > 解决方案 > 使用未初始化的变量是未定义的行为吗?

问题描述

我不知道“未定义的行为”在 Perl 中是否意味着什么,但我想知道在 Perl 中使用未初始化的变量是否会引发不需要的行为。

让我们考虑以下脚本:

use strict;
use warnings FATAL => 'all';

use P4;

my $P4;

sub get {
    return $P4 if $P4;

    # ...connection to Perforce server and initialization of $P4 with a P4 object...
    return $P4;
}   

sub disconnect {
    $P4 = $P4->Disconnect() if $P4;
}   

sub getFixes {
    my $change = shift;

    my $p4 = get();
    return $p4->Run( "fixes", "-c", $change );
}

在这里,用于在连接到 Perforce 服务器后存储 P4 对象的变量$P4在脚本开头没有初始化。但是,无论首先调用哪个函数(getdisconnectgetFixes,变量都将在使用之前进行初始化。

这样做有风险吗?我应该$P4在脚本开头显式初始化变量吗?

标签: perlundefined-behavior

解决方案


只是对所提出的基本问题的几个直接答案。

如果“未定义的行为”在 Perl 中意味着某些东西

是的,Perl 中有这样的概念,并且文档警告过它(比 中的频率要低C)。请参阅脚注†</sup> 中的一些示例。另一方面,在文档中的许多地方,人们发现讨论以

......所以不要那样做。

它经常出现会使解释器感到困惑的事情,并可能导致奇怪且可能无法预测的行为。这些有时是典型的“未定义行为”,即使它们没有直接这样称呼。

主要问题是未初始化的变量如何关联,根据标题和

如果在 Perl 中使用未初始化的变量可能会引发不良行为

这通常不会导致“未定义的行为”,但它当然可能会导致麻烦,并且通常会收到警告。当然,除非变量在这种“使用”中被合法地初始化。例如,

my $x; 
my $z = $x + 3;

将为使用$x而不是为$z(如果warnings打开!)绘制警告。请注意,这仍然会成功,因为它$x被初始化为0. (但在问题中显示的内容中,代码将在此时中止,因为FATAL.)

从这个意义上说,问题中显示的代码似乎很好,因为正如你所说

变量将在使用前被初始化

对未初始化的变量进行真值测试很好,因为一旦声明它就配备了 value undef,在此类测试中是可接受的(和错误的)。

请参阅perlsyn 中的声明中的前几段,以获得关于何时需要或不需要变量的各种摘要defined


†</sup> 文档中特别标记为“未定义”的一些行为列表

  • 在标量上下文中调用排序

    在列表上下文中,这会对 LIST 进行排序并返回排序后的列表值。在标量上下文中,排序的行为是未定义的。

  • 截断长度太大

    如果 LENGTH 大于文件的长度,则行为未定义。

  • 使用不兼容的sysopen标志(无意义)

    O_TRUNCwith的行为O_RDONLY是未定义的。

  • 使用kill向进程列表发送信号,其中可以使用负信号或进程号发送到进程组

    如果 SIGNAL 和 PROCESS 均为负数,则结果未定义。在未来的版本中可能会产生警告。

  • 自动递增和自动递减 (perlop)

    ...在同一语句中修改变量两次将导致未定义的行为。

  • 如果将 hash 插入到中,则使用each进行迭代,尽管它可能很棘手,但表现不佳

    如果在迭代时添加或删除散列的元素,对迭代器的影响是未指定的;例如,条目可能会被跳过或重复——所以不要那样做。删除最近返回的项目总是安全的each,...

    这会绘制运行时警告 (F),在 perldiag 中进行了描述

    在插入后使用each()on hash 而不重置哈希迭代器会导致未定义的行为。

  • 语句修饰符 (perlsyn)用于my

    使用语句修饰符条件或循环构造(例如 )修改的 、 或修改mystate行为是未定义的。ourmy $x if ...

考虑到 UB 的含义,其中一些似乎有点令人印象深刻(可预测)。感谢 ikegami 的评论。此列表的一部分可在此问题中找到。

从本文发布时的当前文档中撬出(v5.32.1)


推荐阅读