14

我刚刚发现(令我惊讶)调用以下函数

function foo()
if false
   fprintf = 1;
else
  % do nothing
end
fprintf('test')

给出和错误Undefined function or variable "fprintf"。我的结论是变量的范围是在运行前确定的(在我有限的理解计算机语言的解释,特别是 Matlab 的工作原理中)。谁能给我一些这方面的背景信息?

编辑

我上面忘记提到的另一个有趣的事情是

function foo()
if false
   fprintf = 1;
else
  % do nothing
end
clear('fprintf')
fprintf('test')

产生Reference to a cleared variable fprintf.

4

4 回答 4

9

MATLAB 在函数运行之前对其进行解析。例如,它会查找变量名称,而不考虑激活(或不激活)这些变量的分支。也就是说,范围不是在运行时确定的。

附录:我不推荐这样做,但我看到很多人用 MATLAB 做我不推荐的事情。但是...考虑一下如果有人定义自己的名为“false”的函数会发生什么。运行前解析器不知道如果调用该函数会发生什么。

于 2012-10-25T18:27:07.160 回答
8

似乎 MATLAB JIT 编译器第一次解析 m 文件时,它会识别函数中声明的所有变量。它似乎并不关心是否在无法访问的代码中声明了所述变量。因此,您的局部fprintf变量会立即隐藏内置函数fprintf。这意味着,就这个函数而言,没有名为 的内置函数fprintf

当然,一旦发生这种情况,函数中的每个引用都fprintf指向局部变量,并且由于该变量实际上从未被创建,因此尝试访问它会导致错误。

清除变量只是清除局部变量,如果它存在,它不会将内置函数带回范围。

要显式调用内置函数,您可以使用该builtin函数。

builtin( 'fprintf', 'test' );

上面的行将始终在 MATLAB 命令行中打印文本,而不考虑可能影响fprintf函数的局部变量。

于 2012-10-25T17:27:30.830 回答
4

有趣的情况。我怀疑是否有关于 MATLAB 解释器如何在这种奇怪情况下工作的详细信息,但文档中有几件事需要注意......

MATLAB 使用的函数优先顺序将变量放在首位:

在假设名称与函数匹配之前,MATLAB 会在当前工作区中检查具有该名称的变量。

当然,在您的示例中,该变量fprintf实际上并不存在于工作区中,因为从未输入过条件语句的该分支。但是,关于变量命名的文档是这样说的:

避免创建与函数同名的变量(例如ijmodecharsizepath)。通常,变量名优先于函数名。如果你创建一个使用函数名的变量,你有时会得到意想不到的结果。

这一定是那些“意外结果”之一,尤其是在实际未创建变量时。结论是 MATLAB 中必须有某种机制在运行时解析文件以确定给定范围内可能存在的变量,其最终结果是函数仍然会被m 文件中出现的变量所掩盖,即使如果它们最终没有出现在工作区中。


编辑:更令人困惑的是,函数喜欢exist并且which甚至不知道函数似乎被遮蔽的事实。在调用之前添加这些行fprintf

exist('fprintf')
which('fprintf')

在错误发生之前给出此输出:

ans =
     5
built-in (C:\Program Files\MATLAB\R2012a\toolbox\matlab\iofun\fprintf)

表示他们仍然看到内置的fprintf.

于 2012-10-25T17:14:38.600 回答
2

这些可能会提供见解:

这可以为您提供一些有关被遮蔽的信息:

which -all

(以下被确认为错误)一个问题是 Workspace 结构和路径上的类具有特定的范围和类型优先级,(如果你是我的话)可能会抓住你。

例如在 2017b 中:

% In C.m, saved in the current directory
classdef C
 properties (Constant)
   x = 100;
 end
end

% In Command window
C.x = 1;
C.x       % 100
 C.x      % 1 (Note the space)
C.x*C.x   % 1
disp(C.x) % 1
于 2018-05-09T18:40:31.037 回答