如何在MATLAB中识别数据存储在数组范围之外的位置?

时间:2015-03-19 17:52:19

标签: arrays matlab matlab-coder

我正在尝试使用MATLAB Coder将代码从Matlab转换为MEX文件。如果我有以下格式的代码段:

x = zeros(a,1)
x(a+1) = 1

然后在Matlab中,这将调整数组的大小以容纳新元素,而在MEX文件中,这将使"索引超出矩阵维度"错误。我希望代码中有很多地方可以发生这种情况。

我想要做的是运行代码的MATLAB版本(不使用编码器),但是MATLAB在调整数组大小时会生成错误或警告,因为我指定了边界之外的东西。 (我可以使用MEX文件查看错误弹出的位置,但这需要在每次更改代码时使用MATLAB Coder重建整个MEX文件,这需要一段时间。)

有办法做到这一点吗?在MATLAB中是否有任何类型的设置将关闭"如果您分配到越界索引"会自动调整大小,或者如果发生这种情况会发出警告?

1 个答案:

答案 0 :(得分:3)

编辑: As of Matlab 2015b,编码器现在将运行时错误检查作为选项(来自Matlab发行说明):

  

在R2015b中,生成的独立库和可执行文件可以检测并报告运行时错误,例如越界数组索引。在   以前的版本,只检测到生成的MEX并报告了运行时间   错误。

     

默认情况下,MEX启用运行时错误检测。通过   默认情况下,独立库禁用运行时错误检测   和可执行文件。

     

为独立启用运行时错误检测   库和可执行文件:

     

在命令行中,使用代码   配置属性RuntimeChecks

     

cfg = coder.config(' lib'); % 要么   ' DLL'或者' exe'

     

cfg.RuntimeChecks = true;

     

codegen -config cfg myfunction

     

使用MATLAB Coder应用程序,在项目构建设置中,   在“调试”选项卡上,选择“生成运行时错误检查”检查   框。

     

生成的库和可执行文件使用fprintf进行写入   错误消息发送到stderr并中止以终止应用程序。如果   fprintf和abort不可用,您必须提供它们。错误   消息是英文的。

     

请参阅Run-Time Error Detection and Reporting in Standalone C/C++ CodeGenerate Standalone Code That Detects and Reports Run-Time Errors

原始回答: 关于声明从double继承的类的注释中的答案,其中subsref方法被重载以禁止增长将是一种很好的方法。

另一种简单的方法是在整个代码中(在每个循环迭代中或在函数的底部)撒上assert命令来断言大小没有超过分配的大小。

例如,如果您的代码格式为:

x = zeros(a,1)
x(a+1) = 1
... lots of other operations

if coder.target('MATLAB')
    assert(isequal(size(x), [a,1]), 'x has been indexed out of bounds')
end

如果分配了扩展数组的任何值,这将使断言失败。

为了使它更加整洁,您甚至可以创建一个边界检查所有您关心的变量的函数,再次包装coder.target if语句。然后你可以在整个代码中撒上这个。

它不像重载double类那样优雅,但另一方面它根本不会给编译代码添加任何开销。当溢出发生时,它也不会准确地给你错误,但它会让你相信代码在各种情况下运行良好。

您可以对分配更有信心的另一种方法是在可能适合的情况下对分配进行自己的界限检查。我在任务中遇到的一个常见问题是这样的。我们有一个已分配的数组,并使用向量赋值从另一个数组中复制数据。例如,请考虑以下情况:

t = char(zeros(5,7));              % Allocate a 5 by 7 char array
tempstring = 'hello to anyone';    % Here's a string we want to put into it.
t(1, 1:numel(tempstring)) = tempstring;  % A valid assignment in MATLAB

>> size(t)
ans =
5    15   

哦,确切地说,你在问题中关注的是:t数组在分配过程中自动调整大小,在MATLAB中有效,但在Coder中创建的代码会导致段错误或MEX错误。另一种方法是使用end函数的强大功能来保持作业整洁(但是被截断)。如果我们将作业更改为:

t(1,1:min(end,numel(tempstring))) = tempstring(1:size(t, 2));

t的大小将保持不变,但分配将被截断。 end的使用允许在分配期间进行边界检查。在某些情况下,这可能是处理问题的一种很好的方法,并且可以让您确信永远不会超出界限,但显然在某些情况下这是非常不受欢迎的(并且不会在MATLAB中给出错误消息)。 )

MATLAB提供的另一个有用的工具是编辑器本身。如果您在代码中使用%#codegen标记,它将指示编辑器的语法检查器突出显示各种代码生成问题,包括您通过索引显然增加数组大小的位置。这无法抓住每一种情况,但这是一个很好的帮助。

Editor example with codegen

最后一点。正如问题中所提到的,Coder生成的MEX文件将为您提供"索引超过矩阵维度"在分配时发生错误,并优雅地退出,甚至告诉您发生错误的原始代码行。从Coder生成的C库没有这样好的行为或边界检查,并且在没有诊断的情况下将完全分段。中间答案是完成您正在做的事情,即将代码作为MEX运行。这对你的问题没有多大帮助(正如你所说,重建MEX可能需要时间),但对于我们这些编写外部C代码的冷酷世界的人来说,能够运行的中间测试MEX找到这些错误是一种救星。

底线是这是MATLAB和Coder生成的C代码之间的行为差​​异,它可能是重大问题的根源。在我自己的代码中,出于这个原因,我对数组访问和增长非常小心。这是一个我希望看到Coder工具本身有所改进的领域,但在编写针对Coder的MATLAB代码时,有一些方法要非常小心。