Main Content

为 C/C++ 代码生成定义变量的最佳做法

用于代码生成的 MATLAB® 代码必须遵循某些限制。定义变量时,请遵循以下最佳做法来优化变量的使用,并避免在代码中生成错误。

在使用变量之前显式定义变量

对于 C/C++ 代码生成,必须显式定义变量值和属性,然后才能在运算中使用这些变量值和属性或将它们作为输出返回。这样做可以防止在未定义变量时出错。

注意

定义的变量默认为局部变量,并且不会在函数调用之间持久存在。要使变量持久存在,请使用 persistent 函数。

初始化新变量有时会导致生成的代码中出现冗余副本。有关详细信息,请参阅Eliminate Redundant Copies of Variables in Generated Code

在所有执行路径中定义变量

您必须在所有执行路径中定义变量,例如由 if 语句指示的执行路径中。以如下 MATLAB 代码为例,它会在将变量用作函数的输入之前定义该变量:

...
if c <= 0
  x = 11;
end
% Later in your code ...
if c > 0
% Use x in the function foo
  foo(x);
end
...
该代码仅在 c <= 0 时对 x 赋值,并且仅在 c > 0 时使用 x。根据 c 的值,以下代码可以在 MATLAB 中正常运行而不出错。但是,当您尝试从此 MATLAB 代码生成 C/C++ 代码时,代码生成会失败,因为代码生成器检测到当 c > 0x 在执行路径中未定义。

要使此代码适合代码生成,请在使用 x 前先对其进行定义:

x = 0;
...
if c <= 0
  x = 11;
end
% Later in your code ...
if c > 0
% Use x in the function foo
  foo(x);
end
...

定义所有结构体字段

您还必须为所有执行路径定义每个结构体字段。以如下 MATLAB 代码为例:

...
if c > 0 
  s.a = 11;
  disp(s);
else
  s.a = 12;
  s.b = 12;
end
% Use s in the function foo
foo(s);
...
if 语句的第一部分仅使用字段 aelse 语句使用字段 ab。此代码可在 MATLAB 中正常工作,但在 C/C++ 代码生成过程中会生成编译错误。为了防止出现此错误,请不要在使用某结构体后向该结构体添加字段。有关详细信息,请参阅用于代码生成的结构体定义

要使此代码适合 C/C++ 代码生成,请在使用之前定义 s 的字段:

...
% Define fields in structure s
s = struct("a", 0, "b", 0);
if c > 0 
  s.a = 11;
  disp(s);
else
  s.a = 12;
  s.b = 12;
end
% Use s in the function foo
foo(s);
...

对变量属性重新赋值时务必小心

您可以在对某些变量初始赋值后用不同的类、大小或复/实性的值对其重新赋值。请参阅变量属性的重新赋值。但是,如果在初始赋值后对变量类型重新赋值,代码通常会在代码生成过程中返回编译错误。一般情况下,赋予每个变量的类、大小、类型和复/实性需是特定的。

定义变量数值数据类型

double 是 MATLAB 中的默认数值数据类型。要定义其他数据类型的变量,必须在定义中用正确的前缀或运算符显式定义数据类型。请注意您使用的数据类型,因为在代码中使用不同数据类型的变量会导致类型不匹配错误。

例如,以下代码将变量 x 定义为双精度值,将 y 定义为 8 位整数:

x = 15;
y = uint8(x);

有关 MATLAB 中支持的类型的详细信息,请参阅数值类型

在对索引变量赋值之前定义矩阵

除非使用 end + 1 索引或者首先将变量定义为可变大小,否则通过写入超出其当前大小的元素来增大变量会导致编译时或运行时错误。请参阅 Generate Code for Growing Arrays and Cell Arrays with end + 1 Indexing (MATLAB Coder)为代码生成定义可变大小数据。在不使用 end + 1 索引或将数组定义为可变大小的情况下,要避免出现与大小相关的错误,请先定义数组的最大大小,然后再为数组的元素赋值。

例如,以下赋值会在代码生成时导致错误:

g = zeros(3,3);
g(5,2) = 14.6;

通过定义足够大的矩阵 g 来更正以下代码:

g = zeros(5,5);
g(5,2) = 14.6;

有关索引矩阵的详细信息,请参阅在代码生成的矩阵索引操作方面与 MATLAB 的不兼容性

目标是使用固定大小的向量对数组进行索引

尽管代码生成支持可变大小数组,但可变大小数组需要额外的内存,这会降低性能。请尽可能使用常量值向量对数组进行索引。例如:

...
% extract 7 elements from A using a constant-value vector
B = A(1:7);
...
在此示例中,代码生成器将识别 B 为固定大小。

如果使用 colon 运算符和变量值对数组进行索引,代码生成器并不总能正确确定数组是固定大小还是可变大小。例如,以下两个数组均为固定大小,与 i 的值无关:

...
% extract 7 elements from A using a fixed-size vector
B = A(i-1:i+5);
C = A(-1+2*i:5+2*i);
...
如果在代码生成时已知 i 的值,代码生成器会将 BC 都识别为固定大小数组。但是,如果在代码生成时 i 的值还未知,代码生成器会将 B 识别为固定大小,而将 C 定义为可变大小。因此,您可以定义一个大小不可更改的数组,即固定大小数组,但代码生成器会将该数组解释并指定为可变大小数组。

在某些情况下,可以重写您的 MATLAB 代码,以强制代码生成器识别定义的不改变大小的数组。例如,您可以重写上面的 C 的定义,以从涉及变量 (i) 的数学运算中提取数组索引表达式,该变量在代码生成时还未知:

...
% extract 7 elements from A using a fixed-size vector
C = A(2*i+(-1:5));
...
重写后,代码生成器会将 C 识别为固定大小数组。

在一些其他代码模式中,数组索引包括影响数组大小的变量,但这些变量在编译时是已知的。在这些情况下,提取的数组实际上是固定大小数组,但代码生成器可能无法识别它,并将其视为可变大小数组。有时,您也可以重写这样的代码来生成固定大小数组。在此示例中,数组 D_varSizeD_fixSize 相同。但是,代码生成器将 D_varSize 定义为可变大小,将 D_fixSize 定义为固定大小:

...
width = 25;              
D_varSize = A(i-width:i+width);  % D_varSize is variable-size if i is unknown at compile time 
D_fixSize = A(i+(-width:width)); % D_fixSize is fixed-size whether or not i is unknown at compile time
...

另请参阅

| |

相关主题