代码生成的元胞数组限制
当您在用于代码生成的 MATLAB® 代码中使用元胞数组时,必须遵守以下限制:
元胞数组元素赋值
在使用某元胞数组元素之前,必须在所有执行路径上对该元素赋值。例如:
function z = foo(n) %#codegen c = cell(1,3); if n < 1 c{2} = 1; else c{2} = n; end z = c{2}; end
将元胞数组传递给函数或从函数返回元胞数组时,代码生成器会将其视为使用元胞数组的所有元素。因此,在将元胞数组传递给函数或从函数返回该元胞数组之前,必须为其所有元素赋值。例如,不允许使用以下代码,因为它没有为 c{2}
赋值,而 c
是函数输出。
function c = foo() %#codegen c = cell(1,3); c{1} = 1; c{3} = 3; end
对元素的赋值必须在所有执行路径上保持一致。不允许使用以下代码,因为 y{2}
在一条执行路径上为 double 类型,而在另一条执行路径上为 char 类型。
function y = foo(n) y = cell(1,3) if n > 1; y{1} = 1 y{2} = 2; y{3} = 3; else y{1} = 10; y{2} = 'a'; y{3} = 30; end
可变大小元胞数组
异构元胞数组不支持
coder.varsize
。如果使用
cell
函数定义固定大小元胞数组,则无法使用coder.varsize
指定元胞数组具有可变大小。例如,以下代码会导致代码生成错误,因为x = cell(1,3)
使x
成为固定大小的 1×3 元胞数组。... x = cell(1,3); coder.varsize('x',[1 5]) ...
您可以将
coder.varsize
与使用花括号定义的元胞数组结合使用。例如:... x = {1 2 3}; coder.varsize('x',[1 5]) ...
要使用
cell
函数创建可变大小的元胞数组,请使用以下代码模式:function mycell(n) %#codegen x = cell(1,n); for i = 1:n x{i} = i; end end
要指定元胞数组的上界,请使用
coder.varsize
。function mycell(n) %#codegen x = cell(1,n); for i = 1:n x{i} = i; coder.varsize('x',[1,20]); end end
使用 cell
定义可变大小元胞数组
对于代码生成,在使用某元胞数组元素之前,必须为其赋值。当您使用 cell
创建可变大小元胞数组(例如 cell(1,n)
)时,MATLAB 会用一个空矩阵对每个元素赋值。然而,代码生成并不会对元素进行赋值。对于代码生成,在您使用 cell
创建可变大小元胞数组后,必须对该元胞数组的所有元素赋值,然后才能使用该元胞数组。例如:
function z = mycell(n, j) %#codegen assert(n < 100); x = cell(1,n); for i = 1:n x{i} = i; end z = x{j}; end
在首次使用元胞数组之前,代码生成器会分析您的代码,以确定是否所有元素均已赋值。如果代码生成器检测到某些元素未赋值,代码生成将失败,并显示错误消息。例如,将 for
循环的上界修改为 j
。
function z = mycell(n, j) %#codegen assert(n < 100); x = cell(1,n); for i = 1:j %<- Modified here x{i} = i; end z = x{j}; end
如果进行了此修改且输入 j
小于 n
,则该函数不会为所有元胞数组元素赋值。代码生成会产生错误:
Unable to determine that every element of 'x{:}' is assigned before this line.
有时,尽管您的代码对元胞数组的所有元素进行了赋值,但代码生成器仍报告此消息,这是因为分析未检测到所有元素均已赋值。请参阅无法确定元胞数组的每个元素都已赋值。
为避免此错误,请遵循以下准则:
当您使用
cell
定义可变大小元胞数组时,请按照以下模式编写代码:function z = mycell(n, j) %#codegen assert(n < 100); x = cell(1,n); for i = 1:n x{i} = i; end z = x{j}; end
以下是针对多维元胞数组的模式:
function z = mycell(m,n,p) %#codegen assert(m < 100); assert(n < 100); assert(p < 100); x = cell(m,n,p); for i = 1:m for j =1:n for k = 1:p x{i,j,k} = i+j+k; end end end z = x{m,n,p}; end
循环计数器的递增或递减量为
1
。在一个循环或一组嵌套循环内定义元胞数组。例如,不允许使用以下代码:
function z = mycell(n, j) assert(n < 50); assert(j < 50); x = cell(1,n); for i = 1:5 x{i} = 5; end for i = 6:n x{i} = 5; end z = x{j}; end
对元胞维度、循环初始值和结束值使用相同的变量。例如,以下代码的代码生成就会失败,因为元胞创建使用的是
n
,而循环结束值使用的是m
:function z = mycell(n, j) assert(n < 50); assert(j < 50); x = cell(1,n); m = n; for i = 1:m x{i} = 2; end z = x{j}; end
重写代码以对元胞创建和循环结束值使用
n
:function z = mycell(n, j) assert(n < 50); assert(j < 50); x = cell(1,n); for i = 1:n x{i} = 2; end z = x{j}; end
按照以下模式创建元胞数组:
x = cell(1,n)
通过使用所需的元胞初始化临时变量,将元胞数组赋给结构体的字段或对象的属性。例如:
不要将元胞数组直接赋给结构体的字段或对象的属性。例如,不允许使用以下代码:t = cell(1,n) for i = 1:n t{i} = i+1; end myObj.prop = t;
myObj.prop = cell(1,n); for i = 1:n myObj.prop{i} = i+1; end
不要在元胞数组构造函数
{}
内使用cell
函数。例如,不允许使用以下代码:x = {cell(1,n)};
为元胞数组元素赋值的元胞数组创建语句和循环赋值语句必须位于同一个唯一执行路径中。例如,不允许使用以下代码。
function z = mycell(n) assert(n < 100); if n > 3 c = cell(1,n); else c = cell(n,1); end for i = 1:n c{i} = i; end z = c{n}; end
要修复此代码,请将赋值循环移入创建元胞数组的代码块内。
function z = cellerr(n) assert(n < 100); if n > 3 c = cell( 1,n); for i = 1:n c{i} = i; end else c = cell(n,1); for i = 1:n c{i} = i; end end z = c{n}; end
元胞数组索引
您不能使用圆括号
()
对元胞数组进行索引。请考虑使用花括号{}
对元胞数组进行索引来访问元胞的内容。您必须使用常量索引或使用具有常量边界的
for
循环对异构元胞数组进行索引。例如,不允许使用以下代码。
x = {1, 'mytext'}; disp(x{randi});
您可以在具有常量边界的
for
循环中对异构元胞数组进行索引,因为代码生成器会展开循环。展开会为每次循环迭代创建循环体的一个单独副本,这使得每次循环迭代中的索引不变。然而,如果for
循环体很大或者有很多迭代,则展开可能增加编译时间和生成无效代码。如果
A
和B
是常数,则下列代码展示了如何在具有常量边界的for
循环中对异构元胞数组进行索引。x = {1, 'mytext'}; for i = A:B disp(x{i}); end
使用 {end + 1} 增大元胞数组
要增大元胞数组 X
,可以使用 X{end + 1}
。例如:
... X = {1 2}; X{end + 1} = 'a'; ...
当您使用 {end + 1}
增大元胞数组时,请遵循以下限制:
在 MATLAB Function 模块中,不要在
for
循环中使用{end + 1}
。仅使用
{end + 1}
。不要使用{end + 2}
、{end + 3}
等。仅对向量使用
{end + 1}
。例如,不允许使用以下代码,因为X
是矩阵,而不是向量:... X = {1 2; 3 4}; X{end + 1} = 5; ...
仅对变量使用
{end + 1}
。在以下代码中,{end + 1}
不会使{1 2 3}
增大。在本例中,代码生成器将{end + 1}
视为超出X{2}
范围的索引。... X = {'a' { 1 2 3 }}; X{2}{end + 1} = 4; ...
当
{end + 1}
在循环中增大元胞数组时,该元胞数组必须是可变大小的。因此,元胞数组必须是同构元胞数组。允许使用以下代码,因为
X
是同构元胞数组。... X = {1 2}; for i=1:n X{end + 1} = 3; end ...
不允许使用以下代码,因为
X
是异构元胞数组。... X = {1 'a' 2 'b'}; for i=1:n X{end + 1} = 3; end ...
元胞数组内容
元胞数组不能包含 mxarrays
。在元胞数组中,不能存储外部函数返回的值。
将元胞数组传递给外部 C/C++ 函数
您不能将元胞数组传递给 coder.ceval
。如果某变量是 coder.ceval
的输入参数,则应将该变量定义为数组或结构体,而不能是元胞数组。
在 MATLAB Function 模块中使用
对于 Simulink® 信号、参数或数据存储内存,不能使用元胞数组。