主要内容

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

解决问题:变量在使用前必须完全定义

问题

与动态定型语言 MATLAB® 不同,C 和 C++ 是静态定型的。这意味着代码生成器必须能够确定 MATLAB 代码中所有变量的类型,以在生成的代码中定义和分配变量。如果代码生成器无法确定您的 MATLAB 代码中的一个或多个变量的类型,代码生成器将返回一条包含以下句子的错误消息:

For code generation, all variables must be fully defined before use.(要进行代码生成,所有变量在使用前都必须完全定义。)

如果您看到的错误消息涉及元胞数组或元胞数组元素,请参阅解决问题:元胞数组元素在使用前必须完全定义

可能的解决方案

要解决此问题,请在所有执行路径中为 MATLAB 代码中的所有变量赋值。这包括其他数据结构体(如结构体字段和类属性)中包含的所有变量。根据您的 MATLAB 代码和您看到的特定错误消息,尝试以下解之一。

为所有执行路径中的变量赋值

在某些情况下,代码生成器无法确定所有变量都在所有执行路径中进行了定义。例如,创建一个 MATLAB 函数 undefinedVariableTest,它接受数值输入 x 并返回 x 的绝对值。

function y = undefinedVariableTest(x) %#codegen
arguments
    x (1,1) double
end
if x == 0
    y = 0;
elseif x < 0
    y = -x;
elseif x > 0
    y = x;
end
end
在 MATLAB 执行中,对 undefinedVariableTest 的调用为 x 的所有值返回一个值。但是,undefinedVariableTest 的代码生成失败,原因是代码生成器找不到 else 语句,因此无法确定 y 在所有可能的执行路径中进行了定义。

要使以下代码适合代码生成,请使用 else 语句强制代码生成器确认 y 在所有可能的执行路径中进行了定义。

function y = undefinedVariableTest(x) %#codegen
arguments
    x (1,1) double
end
if x == 0
    y = 0;
elseif x < 0
    y = -x;
else
    y = x;
end
end

或者,在 if 语句之外为 y 赋予虚拟值。

function y = undefinedVariableTest(x) %#codegen
arguments
    x (1,1) double
end
y = 0;
if x == 0
    y = 0;
elseif x < 0
    y = -x;
elseif x > 0
    y = x;
end
end

为所有结构体字段和类属性赋值

您必须在所有执行路径中定义包含在其他数据类型中的所有变量,并且在使用结构体或类后,您无法更改结构体字段或类属性的数量或格式。此外,对于某些编码模式,代码生成器无法识别包含在另一数据类型中的所有变量都已定义。在这些情况下,请尝试使用不同编码模式重写代码。

结构体字段。在用于代码生成的 MATLAB 代码中,您在读取结构体、对结构体进行索引或将结构体传递给函数后,无法向结构体添加字段。例如,创建一个 MATLAB 函数 undefinedFieldTest,该函数返回结构体 y。如果 x 大于 10,则 undefinedFieldTest 定义结构体 s 的字段 field1 并为其赋值。否则,undefinedFieldTest 定义结构体 sfield1field2 并对其赋值。

function y = undefinedFieldTest(x) %#codegen
arguments
    x (1,1) double
end
if x > 10
    s.field1 = 11;
else
    s.field1 = 12;
    s.field2 = 12;
end
y = s;
end
在 MATLAB 执行中,如果 x 等于或小于 10,则字段 field2 被动态添加到结构体 s 中。但是,当 x 的运行时值未知时,代码生成器必须在代码生成时确定结构体 s 包含的所有字段的类型。代码生成失败,因为代码生成器在某些执行路径中检测到字段 field2 是结构体 s 的一部分,但在其他执行路径中不是。

要使以下代码适合代码生成,请不要在运行时更改结构体所包含的字段的数量或名称。独立于 x 的运行时值定义 s 的所有字段。

function y = undefinedFieldTest(x) %#codegen
arguments
    x (1,1) double
end
s = struct("field1", [], "field2", []);
if x > 10
    s.field1 = 11;
else
    s.field1 = 12;
    s.field2 = 12;
end
y = s;
end
要了解有关在用于代码生成的 MATLAB 代码中使用结构体数据类型的更多信息,请参阅用于代码生成的结构体定义

类属性。对于在循环中为类属性赋值的某些编码模式,代码生成器无法识别所有属性都已定义。例如,创建一个 MATLAB 函数 undefinedPropTest,它接受正整数输入 n,并返回类 MyClass 的一个实例。类 MyClass 有两个属性,即 prop1prop2。函数 undefinedPropTestfor 循环中返回的 myClass 对象的 prop1prop2 赋值。

function y = undefinedPropTest(n) %#codegen
arguments
    n (1,1) double {mustBePositive, mustBeInteger}
end
x = MyClass;
for i = 1:n
    x.prop1 = 1 + i;
    x.prop2 = x.prop1 + 3;
end
y = x;
end
在 MATLAB 执行中,undefinedPropTestn 的所有允许值返回 MyClass 的一个实例。但 undefinedPropTest 的代码生成失败,因为代码生成器无法确定 undefinedPropTest 是否针对 n 的所有值对 prop1prop2 赋值。

要使以下代码适合代码生成,请在 for 循环之前为 MyClass 的所有属性赋予虚拟值。

function y = undefinedPropTest(n) %#codegen
arguments
    n (1,1) double {mustBePositive, mustBeInteger}
end
x = MyClass;
x.prop1 = 0;
x.prop2 = 0;
for i = 1:n
    x.prop1 = 1 + i;
    x.prop2 = x.prop1 + 3;
end
y = x;
end
有关在用于代码生成的 MATLAB 代码中定义类属性时的其他注意事项,请参阅为代码生成定义类属性

将初始值赋给所有持久变量

您必须在所有执行路径中的 MATLAB 代码中定义所有 persistent 变量。例如,创建一个 MATLAB 函数 undefinedPersistentTest,它在 persistent 变量 count 中存储它被调用的次数。要初始化或重置 count,必须使用参量 0 调用 undefinedPersistentTest

function y = undefinedPersistentTest(x)
persistent count;
if x == 0
    count = 0;
else
    count = count + 1;
end
y = count;
end

MATLAB 在第一次遇到持久变量时,会自动将其设置为空矩阵 ([])。因此,对 undefinedPersistentTest 的调用不会生成错误,即使 count 已被赋值也是如此。但是,代码生成器无法在代码生成时确定未初始化的持久变量的大小和类型。因此,undefinedPersistentTest 的代码生成会失败,因为没有为 x 的所有值定义 count

要使以下代码适合代码生成,请使用 isempty 函数为 count 赋值(如果未定义此变量)。

function y = undefinedPersistentTest(x)
arguments
    x (1,1) double
end
persistent count;
if isempty(count)
    count = 0;
end
if x == 0
    count = 0;
else
    count = count + 1;
end
y = count;
end

定义没有赋值的变量

在某些情况下,在生成的代码中通过赋值来定义变量的开销是很大的。通过赋值定义变量也会导致变量的冗余副本出现在生成的代码中。要定义变量类型、大小和复/实性而不带来变量赋值的开销,请使用 coder.nullcopy

如果您使用 coder.nullcopy 来定义变量,您可以生成代码而不必遵循上述可识别的编码模式。以 nullcopyExample 函数为例。由于此函数使用 coder.nullcopy 为类 MyClass 预分配内存,您不必为此类的属性赋予虚拟值。

function y = nullcopyExample(n) %#codegen
arguments
    n (1,1) double {mustBePositive, mustBeInteger}
end
x = coder.nullcopy(MyClass);
for i = 1:n
    x.prop1 = 1 + i;
    x.prop2 = x.prop1 + 3;
end
y = x;
end

注意

请慎用 coder.nullcopy。必须确保为所有变量赋值,包括类属性、结构体字段和数组元素。如果访问未初始化的变量,结果可能是不可预测的。

另请参阅

|

主题