在MATLAB中,如何判断变量输出的代码在哪里?
我有大约10K行的MATLAB代码,大约有4个人正在使用它。在某个地方,有人以典型的方式将变量转储到MATLAB脚本中:
foo
不幸的是,我不知道输出的变量是什么。而输出正在混乱其他更重要的输出。
有什么想法吗?
P.S。有人试过覆盖Standard.out吗?由于MATLAB和Java集成非常紧密,这会起作用吗?我遇到这个问题时在Java中使用的一个技巧是将Standard.out替换为我自己的版本。
答案 0 :(得分:7)
来自维银的mlint遍历是一个好主意。但是,Mlint无法看到动态代码,例如eval()或字符串值数字句柄回调的参数。我在这样的回调中运行这样的输出,其中update_table()在某些条件下返回。
uicontrol('Style','pushbutton', 'Callback','update_table')
你可以将一个方法“打孔”到内置类型,为dbstop提供一个钩子。在Matlab路径的目录中,创建一个名为“@double”的新目录,然后创建一个@ double / display.m文件。
function display(varargin)
builtin('display', varargin{:});
然后你可以做
dbstop in double/display at 2
并运行您的代码。现在,只要显示被省略的分号隐式调用,包括动态代码,就会被调到调试器中。为@double做这件事似乎也涵盖了char和cell。如果显示的是其他类型,则可能需要进行试验。
您可能以相同的方式覆盖内置的disp()。我认为这与Java的System.out流的自定义替换相似。
毋庸置疑,向内置类型添加方法是非标准的,不受支持的,非常容易出错的,并且在调试会话之外要非常小心。
答案 1 :(得分:5)
这是mLint可以帮助您找到的典型模式:
因此,请在编辑器的右侧查看橙色线条。这不仅可以帮助您找到这种优化,还可以找到很多甚至更多。另请注意,您的变量名称会突出显示。
答案 2 :(得分:3)
如果你有一行如:
foo = 2
并且没有“;”最后,输出将被转储到屏幕上,变量名首先出现:
foo =
2
在这种情况下,您应该在文件中搜索字符串“foo =”并找到缺少“;”的行。
如果您看到没有出现变量名称的输出,则可能使用DISP或FPRINTF函数将输出转储到屏幕上。在文件中搜索“disp”或“fprintf”可以帮助您找到数据的显示位置。
如果你看到变量名称为“ans”的输出出现,这是一个计算正在进行的情况,没有放入变量,并且缺少';'在该行的末尾,例如:
size(foo)
一般来说,这对于显示代码中发生的事情是一种不好的做法,因为(正如您已经发现的那样)很难找到将它们放在大块代码中的位置。在这种情况下,找到违规行的最简单方法是使用MLINT,正如其他答案所示。
答案 3 :(得分:3)
我喜欢“dbstop if display”的想法,但这不是我所知道的dbstop选项。
如果一切都失败了,仍有希望。 Mlint是一个好主意,但如果有数千行和许多功能,那么你可能永远找不到罪犯。更糟糕的是,如果这段代码写得很糟糕,那么就会出现数以万计的mlint标志。你将如何缩小范围?
解决方案是在那里展示自己的方式。我会重载显示功能。只是暂时的,但这会奏效。如果输出正以
的形式转储到命令行ans =
stuff
或
foo =
stuff
然后它已经显示出来了。如果它只是出现
stuff
然后disp是罪魁祸首。为什么这有关系?超负荷罪犯。在MATLAB搜索路径之上的某个目录中创建一个新目录,名为@double(假设输出是一个双变量。如果是字符,那么你需要一个@char目录。)不要放@在MATLAB搜索路径上双目录本身,只需将它放在路径上的某个目录中。
在此目录中,放置一个名为disp.m或display.m的新m文件,具体取决于您对命令行输出的确定。 m文件的内容将是对内置函数的调用,这将允许您在输入上调用内置版本的disp或display。
现在,在新功能中设置一个调试点。每次输出到屏幕时,都会调用此函数。如果有多个事件,您可能需要使用调试器才能继续处理,直到罪犯被困。最终,这个过程将陷入进攻线。请记住,您在调试器中!使用调试器确定调用disp的函数和位置。您可以退出显示或显示,或者只查看dbstack的内容以查看发生了什么。
完成所有操作并修复问题后,请删除此额外目录以及您放入的显示/显示功能。
答案 4 :(得分:1)
您可以将mlint作为函数运行并解释结果。
>> I = mlint('filename','-struct');
>> isErrorMessage = arrayfun(@(S)strcmp(S.message,...
'Terminate statement with semicolon to suppress output (in functions).'),I);
>>I(isErrorMessage ).line
这只会在该单个文件中找到缺少的分号。所以这必须在从某个主函数调用的文件(函数)列表上运行。
如果要查找对disp()或fprintf()的调用,则需要读取文件的文本并使用常规表达式来查找调用。
注意:如果您使用的是脚本而不是函数,则需要将上述消息更改为:'使用分号终止语句以禁止输出(在脚本中)。'
答案 5 :(得分:1)
Andrew Janke的超载是一个非常有用的提示 唯一的另一件事是代替使用dbstop我发现以下工作更好,原因很简单,只要在没有写入任何内容的情况下,每次调用display.m时,在display.m中停止都将导致执行暂停。
这样,只有在调用display来写一个非空字符串时才会触发stop,并且你不必逐步完成可能非常大量无用的显示调用
function display(varargin)
builtin('display', varargin{:});
if isempty(varargin{1})==0
keyboard
end
答案 6 :(得分:1)
定位此类事物的一种万无一失的方法是迭代地逐步调试调试器中的代码,观察输出。这将按如下方式进行:
虽然很痛苦,但除非你有大量的功能/脚本,否则你会以相对较快的速度找到这条线,这无论如何都是不好的做法。如果脚本是这样的,您可以使用一种分区方法以类似的方式定位函数中的行。这将涉及在开始时设置一个断点,然后是一半,并注意函数的哪一半产生输出,然后再次减半,依此类推,直到找到该线。
答案 7 :(得分:1)
我用更小的代码解决了这个问题并且它是一个bugger,所以即使OP找到他们的解决方案,我也会发布一个我学到的小作弊。
1)在Matlab命令提示符下,启用“更多”。
more on
2)将窗口的prompt-y / terminal-y部分调整为仅高度的文本行。
3)运行代码。它将在需要打印的任何地方停止,因为没有打印空间(更多是在[空格]或[向下]按下时阻塞)。
4)按[ctrl] - [C]在无法打印的位置终止程序。
5)将提示区域恢复为正常大小。从跟踪顶部开始,单击红色文本中的可单击位。这些是你潜在的罪魁祸首。 (当然,您可能需要按下[down]等来传递代码实际打算用于打印内容的部分。)
答案 8 :(得分:0)
您需要遍历所有m文件(可能使用递归函数或unix('find -type f -iname * .m'))。在每个文件名上调用mlint:
r = mlint(filename);
r将是一个带有消息字段的(可能是空的)结构。查找以“使用分号终止语句以抑制输出”开头的消息。