解决问题:变量在使用前必须完全定义
问题
与动态定型语言 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
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
定义结构体 s
的 field1
和 field2
并对其赋值。
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
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 函数 undefinedPropTest
,它接受正整数输入 n
,并返回类 MyClass
的一个实例。类 MyClass
有两个属性,即 prop1
和 prop2
。函数 undefinedPropTest
为 for
循环中返回的 myClass
对象的 prop1
和 prop2
赋值。
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
undefinedPropTest
为 n
的所有允许值返回 MyClass
的一个实例。但 undefinedPropTest
的代码生成失败,因为代码生成器无法确定 undefinedPropTest
是否针对 n
的所有值对 prop1
和 prop2
赋值。要使以下代码适合代码生成,请在 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 代码中定义所有 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
。必须确保为所有变量赋值,包括类属性、结构体字段和数组元素。如果访问未初始化的变量,结果可能是不可预测的。