代码生成的元胞数组限制
当您在用于代码生成的 MATLAB® 代码中使用元胞数组时,必须遵守以下限制。
分配一致的元素类型
分配给元胞数组元素的值类型在所有执行路径中必须相同。以 inconsistentTypeError
函数为例。此函数的代码生成失败,因为 ca{2}
在执行路径中是 double
,而在另一个执行路径中是 char
。
function out = inconsistentTypeError(n) %#codegen ca = cell(1,3); if n > 1 ca{1} = 1; ca{2} = 2; ca{3} = 3; else ca{1} = 10; ca{2} = 'a'; ca{3} = 30; end out = ca{1}; end
可变大小元胞数组必须为同构元胞数组
当您为包含元胞数组的 MATLAB 函数生成代码时,代码生成器会将每个元胞数组分类为同构或异构。通常,代码生成器将包含相同类型元素的元胞数组归类为同构,将包含不同类型元素的元胞数组归类为异构。要了解有关代码生成器如何处理同构和异构元胞数组的更多信息,请参阅Code Generation for Cell Arrays。
您可以使用 coder.varsize
将同构元胞数组定义为可变大小,并为可变大小元胞数组设置上界。例如,以下代码将 caX
和 caY
从固定大小的 1x3
元胞数组更改为可变大小元胞数组,其中第二个维度的大小最大为 5 (1x:5
)。
... caX = {1 2 3}; caY = cell(1,3); coder.varsize('caX',[1 5]) coder.varsize('caY',[1 5]) ...
为所有元胞数组元素赋值
在使用元胞数组之前,必须在所有执行路径上对所有元胞数组元素赋值。当您使用 cell
函数创建可变大小元胞数组时,元胞数组元素的大小和类型在生成的代码中未定义。因此,在要进行代码生成的 MATLAB 代码中,必须确保将初始值赋给为使用 cell
函数创建的所有可变大小元胞数组的所有元素。以 incompleteAssignmentError
函数为例。此函数的代码生成失败,因为代码生成器检测到 ca{2}
函数返回的元素未在 n
小于 5
的执行路径中定义。
function out = incompleteAssignmentError(n) %#codegen ca = cell(1,2); if n < 5 ca{1} = 0; else ca{2} = 3; end out = ca{2}; end
有时,即使您的 MATLAB 代码对元胞数组的所有元素进行了赋值,代码生成也会失败,因为代码生成器无法识别所有元胞数组元素都已赋值。通常,使用 cellArrayPatternExample
中所示的编码模式对使用 cell
创建的可变大小元胞数组的元素赋值。
function out = cellArrayPatternExample(n) %#codegen ca = cell(1,n); for i = 1:n ca{i} = i; end out = ca{n}; end
有关可用于确保定义所有元胞数组元素的其他模式,请参阅解决问题:元胞数组元素在使用前必须完全定义。
在与 cell
函数相同的执行路径中赋予初始值
使用 cell
函数创建元胞数组时,必须将为元胞数组元素赋予初始值的循环包含在与创建该元胞数组的 cell
函数相同的唯一执行路径中。例如,函数 cellLoopError
的代码生成会失败,因为将初始值赋给元胞数组 ca
的元素的 for
循环没有出现在创建该元胞数组的 cell
函数所在的唯一执行路径中。
function out = cellLoopError(n) %#codegen if n < 5 ca = cell(1,n); else ca = cell(n,1); end for i = 1:n ca{i} = i; end out = ca; end
要解决此问题,请在包含创建每个元胞数组的 cell
函数的代码块中将初始值赋给元胞数组元素。
function out = cellLoopExample(n) %#codegen if n < 5 ca = cell(1,n); for i = 1:n ca{i} = 0; end else ca = cell(n,1); for i = 1:n ca{i} = 0; end end for i = 1:n ca{i} = i; end out = ca{n}; end
要在对象属性或结构体字段中将初始值赋给可变大小的元胞数组,请使用临时变量
使用 cell
函数创建可变大小元胞数组时,必须先将初始值赋给元胞数组的所有元素,然后在对象属性或结构体字段中使用该数组。例如,函数 fieldAssignmentError
的代码生成会失败,因为它直接将初始值赋给结构体字段中的元胞数组元素。
function out = fieldAssignmentError(n) %#codegen s.field = cell(1,n); for i = 1:n s.field{i} = i+1; end out = s.field{n}; end
function out = fieldAssignmentExample(n) %#codegen ca = cell(1,n); for i = 1:n ca{i} = 0; end s.field = ca; for i = 1:n s.field{i} = i+1; end out = s.field{n}; end
要对异构数组进行索引,请使用常量索引或使用具有常量边界的 for
循环
当您为包含元胞数组的 MATLAB 函数生成代码时,代码生成器会将每个元胞数组分类为同构或异构。通常,代码生成器将包含相同类型元素的元胞数组归类为同构,将包含不同类型元素的元胞数组归类为异构。要了解有关代码生成器如何处理同构和异构元胞数组的更多信息,请参阅Code Generation for Cell Arrays。
您必须使用常量索引或使用具有常量边界的 for
循环对异构元胞数组进行索引。例如,函数 cellIndexingError
的代码生成会失败,因为索引不是常量。
function cellIndexingError(n) %#codegen ca = {1 "a" 2 5:7 3 "c"}; disp(ca{n}); end
您可以通过使用具有常量边界的 for
循环对异构元胞数组进行索引,因为代码生成器会展开循环,这意味着它为每个循环迭代创建一个循环体的单独副本。
function cellIndexingExample(n) %#codegen ca = {1 "a" 2 5:7 3 "c"}; for i = 1:6 if i == n disp(ca{i}); end end end
注意
如果 for
循环体很大或者有很多迭代,则展开可能增加编译时间和生成无效代码。
要使用 {end + 1} 增大元胞数组,请使用特定编码模式
代码生成通过在用于代码生成的 MATLAB 代码中使用 {end + 1}
来支持增大元胞数组。例如,您可以为函数 growCellArray
生成代码,该函数使用 {end + 1}
来增大数组 ca
。
function out = growCellArrayExample(n) %#codegen ca = {1 2}; for i = 1:n ca{end+1} = 3+i; end out = ca{n}; end
当您使用 {end + 1}
在 MATLAB 代码中增大元胞数组以生成代码时,您必须遵守以下限制:
您只能通过为
{end + 1}
元素赋值来增大元胞数组。不支持为后续元素赋值,如{end + 2}
。您只能使用
{end + 1}
来增大元胞数组向量。例如,函数growMatrixError
的代码生成失败,因为ca
是矩阵,而不是向量。function ca = growMatrixError %#codegen ca = {1 2; 3 4}; ca{1,end+1} = 5; end
{end + 1}
必须紧跟在变量后。例如,growArraySubscriptError
的代码生成会失败,因为{end + 1}
出现在ca{2}
旁边,而不是ca
旁边。要解决此问题,请将要修改的元胞数组的元素设置为临时变量。然后,使用function out = growArraySubscriptError(x) %#codegen ca = {'a' { 1 2 3 }}; ca{2}{end+1} = x; out = ca{2}{4}; end
{end + 1}
增大临时变量。使用coder.varsize
以允许修改后的元胞数组元素的大小发生变化。function out = growArrayExampleA(x) %#codegen ca = {'a' {1 2 3}}; coder.varsize('ca{2}') temp = ca{2}; temp{end+1} = x; ca{2} = temp; out = ca{2}{4}; end
或者,通过使用数组串联而不是使用
{end + 1}
来添加新元素。function out = growArrayExampleB(x) %#codegen ca = {'a' {1 2 3}}; coder.varsize('ca{2}') ca{2} = [ca{2} {x}]; out = ca{2}{4}; end
如果使用
{end + 1}
在循环中增大元胞数组,则元胞数组必须是同构的,这意味着所有元胞数组元素必须为同一类型。例如,函数growHeterogeneousError
的代码生成会失败,因为元胞数组ca
包含类型为string
和类型为double
的元素。要了解有关代码生成器如何处理同构和异构元胞数组的更多信息,请参阅Code Generation for Cell Arrays。function out = growHeterogeneousError(n) %#codegen ca = {1 2 "a"}; for i = 1:n ca{end+1} = 3+i; end out = ca; end
要直接对元胞数组进行迭代,元胞数组的第一个维度必须为 1
在 MATLAB 中,您可以直接对任意维数的元胞数组进行迭代。例如,假设有函数 directIterationError
,该函数对一个 3×4 元胞数组进行迭代并显示每列的内容。此函数的代码生成会失败,因为数组 ca
的第一个维度不是 1
。
function directIterationError ca = {1 2 3 4; "five" "six" "seven" "eight"; 9 10 11 12}; for i = ca disp(i); end end
要在 MATLAB 代码中迭代第一个维度不是 1
的元胞数组以生成代码,请遍历每个元胞数组维度的大小,而不是元胞数组本身。
function iterationExample %#codegen ca = {1 2 3 4; "five" "six" "seven" "eight"; 9 10 11 12}; for i = 1:size(ca,1) for j = 1:size(ca,2) disp(ca{i,j}); end end end
不要使用圆括号 ()
对元胞数组进行索引
在用于代码生成的 MATLAB 代码中,不能使用圆括号 ()
对元胞数组进行索引。使用花括号 {}
访问元胞内容。
不要在元胞数组构造函数 {}
中调用 cell
函数
代码生成不支持在元胞数组构造函数 {}
中使用 cell
函数。因此,函数 cellCellError
的代码生成失败。
function out = cellCellError(n) %#codegen ca = {cell(1,n) cell(1,n)}; for i = 1:n ca{1}{i} = i+1; ca{2}{i} = i+2; end out = ca; end
要创建包含其他元胞数组的元胞数组,请在创建外部数组之前初始化每个内部元胞数组的所有元素。然后,您可以直接访问内部数组的元素。
function out = cellCellExample(n) %#codegen x = cell(1,n); y = cell(1,n); for i = 1:n x{i} = 0; y{i} = 0; end ca = {x y}; for i = 1:n ca{1}{i} = i+1; ca{2}{i} = i+2; end out = ca{1}{n}+ca{2}{n}; end
不要在元胞数组中存储 mxArray
数据
在用于代码生成的 MATLAB 代码中,不能在元胞数组中存储 MATLAB 数组(亦称 mxArray
)。当您使用 coder.extrinsic
调用外部函数时,被调函数的运行时输出为 mxArray
。因此,如果不先将外部函数的输出转换为已知类型,就无法将其存储在元胞数组中。请参阅使用 mxArray。
不要使用 coder.ceval
将元胞数组传递给外部 C/C++ 函数
代码生成不支持使用 coder.ceval
将元胞数组传递给外部 C/C++ 函数。如果元胞数组是 coder.ceval
的输入参量,请将元胞数组重新定义为普通数组或结构体。