Main Content

本页翻译不是最新的。点击此处可查看最新英文版本。

无法确定元胞数组的每个元素都已赋值

问题

您会看到以下消息之一:

无法确定 'y' 的每个元素都在此行之前
进行了赋值。
无法确定 'y' 的每个元素都在退出函数
之前进行了赋值。
无法确定 'y' 的每个元素都在退出递归
调用的函数之前都已进行了赋值。

原因

对于代码生成,在使用某元胞数组元素之前,必须为其赋值。当您使用 cell 创建可变大小元胞数组(例如 cell(1,n))时,MATLAB® 会用一个空矩阵对每个元素赋值。然而,代码生成并不会对元素进行赋值。对于代码生成,在您使用 cell 创建可变大小元胞数组后,必须对该元胞数组的所有元素赋值,然后才能使用该元胞数组。

在首次使用元胞数组之前,代码生成器会分析您的代码,以确定是否所有元素均已赋值。当代码遵循以下模式时,代码生成器会检测到所有元素都已赋值:

function z = CellVarSize1D(n, j)
%#codegen
x = cell(1,n);   
for i = 1:n
    x{i} = i;
end
z = x{j};
end

以下是针对多维元胞数组的模式:

function z = CellAssign3D(m,n,p)
%#codegen
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

如果代码生成器检测到某些元素未赋值,代码生成将失败。有时,尽管您的代码对元胞数组的所有元素进行了赋值,代码生成也会失败,因为分析没有检测到所有元素都赋值。

以下是代码生成器无法检测到元素已赋值的示例:

  • 元素在不同循环中赋值

    ...
    x = cell(1,n)
    for i = 1:5
        x{i} = 5;
    end
    for i = 6:n
        x{i} = 7;
    end 
    ...             

  • 定义循环结束值的变量与定义元胞维度的变量不同。

    ...
    x = cell(1,n);
    m = n;
    for i = 1:m
        x{i} = 2;
    end 
    ...                 

有关详细信息,请参阅使用 cell 定义可变大小元胞数组

解决方法

尝试以下解决方法之一:

使用可识别的模式为元素赋值

如果可能,重写您的代码以遵循以下模式:

...
x = cell(1,n);   
for i = 1:n
    x{i} = i;
end
z = x{j};
...

使用 repmat

有时,您可以使用 repmat 来定义可变大小的元胞数组。

以如下定义可变大小元胞数组的代码为例。它将 1 赋值给奇数元素,将 2 赋值给偶数元素。

function z = repDefine(n, j)
%#codegen
c =cell(1,n);
for i = 1:2:n-1
    c{i} = 1;
end
for i = 2:2:n
    c{i} = 2;
end
z = c{j};

代码生成不允许以下代码,因为:

  • 多个循环为元素赋值。

  • 循环计数器不是按 1 递增。

重写代码,首先使用 cell 创建第一个元素为 1,第二个元素为 2 的 1×2 元胞数组。然后,使用 repmat 创建一个可变大小的元胞数组,其元素值在 1 和 2 之间交替。

function z = repVarSize(n, j)
%#codegen
c = cell(1,2);
c{1} = 1;
c{2} = 2;
c1= repmat(c,1,n);
z = c1{j};
end

您可以使用 repmat 将初始为空的可变大小元胞数组传入或传出函数。使用以下模式:

function x = emptyVarSizeCellArray
x = repmat({'abc'},0,0);
coder.varsize('x');
end

以下代码表示 x 是由 1x3 个字符组成的空的可变大小元胞数组,可以传入或传出函数。

使用 coder.nullcopy

最后,您还可以使用 coder.nullcopy 来指示代码生成器可以为元胞数组分配内存,而无需初始化内存。例如:

function z = nulcpyCell(n, j)
%#codegen
c =cell(1,n);
c1 = coder.nullcopy(c);
for i = 1:4
    c1{i} = 1;
end
for i = 5:n
    c1{i} = 2;
end
z = c1{j};
end

请慎用 coder.nullcopy。如果访问未初始化的内存,结果是不可预测的。

另请参阅

| |

相关主题