使用 MATLAB Coder 生成 C 代码
在本教程中,您将使用 MATLAB® Coder™ 为 MATLAB 函数生成一个静态 C 库。首先生成只能接受具有固定预分配大小的输入的 C 代码。然后生成可以接受许多不同大小的输入的 C 代码。
您还可以使用 codegen
命令在 MATLAB 命令行中生成代码。有关此工作流的教程,请参阅通过命令行生成 C 代码。
MATLAB Online™ 不支持 MATLAB Coder。要在 MATLAB Online 中生成 C/C++ 代码,请使用 codegen
命令。
教程文件:欧几里德距离
打开此示例以获取本教程的文件。
教程文件的描述
本教程使用 euclidean_data.mat
、euclidean.m
和 test.m
文件。
MATLAB 数据文件
euclidean_data.mat
包含两段数据:三维欧几里德空间中的一个点以及三维欧几里德空间中的一组其他点。更具体地说:x
是一个3
×1
列向量,表示三维欧几里德空间中的一个点。cb
是一个3
×216
数组。cb
中的每列都表示三维欧几里德空间中的一个点。
MATLAB 文件
euclidean.m
包含euclidean
函数,该函数在本示例中实现核心算法。该函数接受x
和cb
作为输入。它计算x
和cb
中每个点之间的欧几里德距离,并返回以下量:列向量
y_min
,它等于cb
中表示与x
距离最近的点的列。列向量
y_max
,它等于cb
中表示与x
距离最远的点的列。二维向量
idx
,它包含cb
中向量y_min
和y_max
的列索引。二维向量
distance
,它包含计算出的到x
的最小和最大距离。
function [y_min,y_max,idx,distance] = euclidean(x,cb) % Initialize minimum distance as distance to first element of cb % Initialize maximum distance as distance to first element of cb idx(1)=1; idx(2)=1; distance(1)=norm(x-cb(:,1)); distance(2)=norm(x-cb(:,1)); % Find the vector in cb with minimum distance to x % Find the vector in cb with maximum distance to x for index=2:size(cb,2) d=norm(x-cb(:,index)); if d < distance(1) distance(1)=d; idx(1)=index; end if d > distance(2) distance(2)=d; idx(2)=index; end end % Output the minimum and maximum distance vectors y_min=cb(:,idx(1)); y_max=cb(:,idx(2)); end
MATLAB 脚本
test.m
将数据文件euclidean_data.mat
加载到工作区中。接着,它调用函数euclidean
来计算y_min
、y_max
、idx
和distance
。然后,脚本在命令行中显示计算出的量。加载
euclidean_data.mat
是在调用核心算法之前执行的预处理步骤。显示结果是后处理步骤。% Load test data load euclidean_data.mat % Determine closest and farthest points and corresponding distances [y_min,y_max,idx,distance] = euclidean(x,cb); % Display output for the closest point disp('Coordinates of the closest point are: '); disp(num2str(y_min')); disp(['Index of the closest point is ', num2str(idx(1))]); disp(['Distance to the closest point is ', num2str(distance(1))]); disp(newline); % Display output for the farthest point disp('Coordinates of the farthest point are: '); disp(num2str(y_max')); disp(['Index of the farthest point is ', num2str(idx(2))]); disp(['Distance to the farthest point is ', num2str(distance(2))]);
提示
您可以使用 MATLAB Coder 从 MATLAB 函数生成代码。不支持从 MATLAB 脚本生成代码。
请使用测试脚本将预处理和后处理步骤与实现核心算法的函数分隔开。这种做法使您能够轻松地重用您的算法。您需要为实现核心算法的 MATLAB 函数生成代码。不需要为测试脚本生成代码。
为 MATLAB 函数生成 C 代码
运行原始 MATLAB 代码
在 MATLAB 中运行测试脚本 test.m
。输出显示 y
、idx
和 distance
。
Coordinates of the closest point are: 0.8 0.8 0.4 Index of the closest point is 171 Distance to the closest point is 0.080374 Coordinates of the farthest point are: 0 0 1 Index of the farthest point is 6 Distance to the farthest point is 1.2923
使 MATLAB 代码适用于代码生成
MATLAB 编辑器中的代码分析器会在您输入代码时持续检查代码。它会报告问题,并提出修改建议,以最大程度地提高性能和可维护性。
在 MATLAB 编辑器中打开
euclidean.m
。MATLAB 编辑器右上角的代码分析器消息指示标记为绿色。分析器未在代码中检测到错误、警告或改进机会。在函数声明后面添加
%#codegen
指令:function [y,idx,distance] = euclidean(x,cb) %#codegen
%#codegen
指令提示代码分析器识别特定于代码生成的警告和错误。代码分析器消息指示标记变为红色,表示它检测到代码生成问题。
要查看警告消息,请将光标移到带下划线的代码片段上。警告指示,代码生成要求先对变量
idx
和distance
进行完全定义,然后才可以对它们进行下标索引。出现这些警告是因为代码生成器必须在这些变量在代码中首次出现时确定其大小。要解决此问题,请使用ones
函数同时分配和初始化这些数组。% Initialize minimum distance as distance to first element of cb % Initialize maximum distance as distance to first element of cb idx = ones(1,2); distance = ones(1,2)*norm(x-cb(:,1));
代码分析器消息指示标记再次变为绿色,表示它没有再检测到任何代码生成问题。
有关使用代码分析器的详细信息,请参阅使用代码分析器检查代码中的错误和警告。
保存文件。
现在您即可使用 MATLAB Coder 编译您的代码。此处,编译指从您的 MATLAB 代码生成 C/C++ 代码。
注意
编译 MATLAB 代码指从 MATLAB 代码生成 C/C++ 代码。在其他情况下,“编译”可能指 C/C++ 编译器的操作。
打开 MATLAB Coder 并选择源文件
在 MATLAB 工具条的 App 选项卡上,点击代码生成下的 MATLAB Coder 图标。该 App 会打开选择源文件页面。
在选择源文件页面中,输入或选择入口函数
euclidean
的名称。入口函数是顶层 MATLAB 函数,您可以从中生成代码。该 App 将使用默认名称euclidean.prj
在当前文件夹中创建一个工程。点击下一步以转到定义输入类型步骤。App 对入口函数运行代码分析器(您已在前面的步骤中运行过)和代码生成就绪工具。代码生成就绪工具会筛查 MATLAB 代码中是否存在代码生成不支持的功能和函数。如果 App 发现问题,它将打开检查代码就绪性页面,您可以在其中查看和解决问题。在此示例中,由于 App 没有检测到问题,因此将打开定义输入类型页面。有关详细信息,请参阅代码生成就绪工具。
注意
代码分析器和代码生成就绪工具可能无法检测到所有代码生成问题。消除这两个工具检测到的错误或警告后,请使用 MATLAB Coder 生成代码,以确定您的 MATLAB 代码是否存在其他合规性问题。
C/C++ 代码生成支持的某些 MATLAB 内置函数和工具箱函数、类以及 System object 有特定的代码生成限制。这些限制和相关使用说明列在其对应参考页的扩展功能部分。有关详细信息,请参阅 C/C++ 代码生成支持的函数和对象。
定义输入类型
由于 C 使用静态类型,因此在代码生成时(也称为编译时),代码生成器必须确定 MATLAB 文件中所有变量的类、大小和复/实性。因此,您必须指定所有入口函数输入的属性。要指定输入属性,您可以:
指示 App 通过提供使用样本输入调用入口函数的脚本来自动确定输入属性。
直接指定属性。
在此示例中,要定义输入 x
和 cb
的属性,请指定测试文件 test.m
,代码生成器使用该文件来自动定义类型:
输入或选择测试文件
test.m
。点击自动定义输入类型。
测试文件
test.m
会使用预期的输入类型调用入口函数euclidean
。App 确定输入x
为double(3x1)
,输入cb
为double(3x216)
。点击下一步以转到检查运行时问题步骤。
检查运行时问题
检查运行时问题步骤从您的入口函数生成 MEX 文件,然后运行 MEX 函数并报告问题。MEX 函数是可从 MATLAB 内部调用的生成的代码。执行此步骤是一个很好的做法,因为您可以检测并解决在生成的 C 代码中更难诊断出来的运行时错误。默认情况下,MEX 函数包括内存完整性检查。这些检查执行数组边界和维度检查,还检测为 MATLAB 函数生成的代码中是否存在内存完整性冲突问题。有关详细信息,请参阅Control Run-Time Checks。
为了将 MATLAB 代码转换为高效的 C/C++ 源代码,代码生成器引入了优化,在某些情况下,这会导致生成的代码与原始源代码在行为上有所不同。请参阅生成的代码和 MATLAB 代码之间的差异。
要打开检查运行时问题对话框,请点击检查问题箭头
。
在 检查运行时问题对话框中,指定测试文件,或输入使用示例输入调用入口函数的代码。对于此示例,请使用您用来定义输入类型的测试文件
test
。点击检查问题。
App 将生成一个 MEX 函数。它运行测试脚本
test
,将对euclidean
的调用替换为对生成的 MEX 的调用。如果 App 在 MEX 函数生成或执行过程中检测到问题,它将提供警告和错误消息。您可以点击这些消息,导航到有问题的代码并修复问题。在本示例中,App 未检测到问题。默认情况下,该 App 会收集行执行计数。这些计数有助于您了解测试文件
test.m
执行euclidean
函数的效果。要查看行执行计数,请点击查看 MATLAB 行执行计数。App 编辑器在代码左侧显示彩色条。要将彩色突出显示扩展到代码并查看行执行计数,请将光标放在彩色条上。特定绿色底色表示此代码的行执行计数落在特定范围内。在本例中,
for
循环执行 215 次。有关如何解释行执行计数和关闭计数集合的信息,请参阅Collect and View Line Execution Counts for Your MATLAB Code。点击下一步以转到生成代码步骤。
注意
在从您的 MATLAB 代码生成独立的 C/C++ 代码之前,请生成 MEX 函数。运行生成的 MEX 函数,并确保它具有与您的 MATLAB 函数相同的运行时行为。如果生成的 MEX 函数的执行结果不同于 MATLAB 的结果,或者出错,您必须先修复这些问题,然后生成独立的代码。否则,您生成的独立代码可能不可靠并且具有未定义的行为。
生成 C 代码
要打开生成对话框,请点击生成箭头
。
在生成对话框中,将编译类型设置为 静态库 (.lib),将语言设置为 C。对其他工程编译配置设置使用默认值。
您可以选择生成 MEX 函数或其他 C/C++ 编译类型,而不是生成 C 静态库。MEX 和 C/C++ 编译类型可使用不同工程设置。当您在 MEX 和 C/C++ 代码生成之间切换时,请确认您选择的设置。
点击生成。
MATLAB Coder 会在
中生成独立的 C 静态库work
\codegen\lib\euclideaneuclidean
。
是包含您的教程文件的文件夹。MATLAB Coder 指示代码生成成功。它在页面左侧显示源 MATLAB 文件和生成的输出文件。在变量选项卡上,它显示有关 MATLAB 源变量的信息。在目标编译日志 选项卡上,它会显示编译日志,包括 C/C++ 编译器警告和错误。默认情况下,在代码窗口中,该 App 将显示 C 源代码文件work
euclidean.c
。要查看不同的文件,请在源代码或输出文件窗格中,点击文件名称。点击查看报告在报告查看器中查看报告。如果代码生成器在代码生成过程中检测到错误或警告,报告将说明问题并提供有问题的 MATLAB 代码的链接。有关详细信息,请参阅Code Generation Reports。
点击下一步打开完成工作流页面。
查看“完成工作流”页面
完成工作流页面指示已成功生成代码,它提供工程摘要以及指向生成的输出的链接。
将生成的 C 代码与原始 MATLAB 代码进行比较
要将生成的 C 代码与原始 MATLAB 代码进行比较,请在 MATLAB 编辑器中打开 C 文件 euclidean.c
和 euclidean.m
文件。
关于生成的 C 代码的重要信息:
函数签名为:
void euclidean(const double x[3], const double cb[648], double y_min[3], double y_max[3], double idx[2], double distance[2])
const double x[3]
对应于您的 MATLAB 代码中的输入x
。x
的大小为3
,对应于您在从 MATLAB 代码生成代码时使用的示例输入的总大小 (3×1)。const double cb[648]
对应于您的 MATLAB 代码中的输入cb
。cb
的大小为648
,对应于您在从 MATLAB 代码生成代码时使用的示例输入的总大小 (3×216)。在本例中,生成的代码使用一维数组来表示 MATLAB 代码中的二维数组。生成的代码有四个额外的输入参数:数组
y_min
、y_max
、idx
和distance
。这些数组用于返回输出值。它们对应于原始 MATLAB 代码中的输出参数y_min
、y_max
、idx
和distance
。代码生成器将保留您的函数名称和注释。如果可能,代码生成器会保留您的变量名称。
注意
如果您的 MATLAB 代码中的某个变量设置为常量值,它在生成的 C 代码中将不会显示为变量。在这种情况下,生成的 C 代码将包含该变量的实际值。
使用 Embedded Coder®,您可以在 MATLAB 代码和生成的 C/C++ 代码之间进行交互式追溯。请参阅Interactively Trace Between MATLAB Code and Generated C/C++ Code (Embedded Coder)。
为可变大小输入生成 C 代码
您为 euclidean.m
生成的 C 函数只能接受与您在代码生成期间指定的样本输入具有相同大小的输入。但是,对应的 MATLAB 函数的输入数组可以具有任意大小。在本教程的此部分,您将从 euclidean.m
中生成接受可变大小输入的 C 代码。
假设您希望生成的 C 代码中的 x
和 cb
的维度具有以下属性:
x
和cb
的第一个维度的大小为可变大小,但不超过3
。x
的第二个维度具有固定大小,其值为1
。cb
的第二个维度的大小为可变大小,但不超过216
。
要指定这些输入属性,请执行以下操作:
在定义输入类型 步骤中,像以前一样输入测试文件
test.m
,然后点击自动定义输入类型。测试文件使用预期的输入类型调用入口函数euclidean.m
。App 确定输入x
为double(3x1)
,输入cb
为double(3x216)
。这些类型指定固定大小的输入。点击输入类型设定并编辑它们。您可以通过使用
:
前缀来指定可变大小,最高不超过指定的限制。例如,:3
表示对应维度具有可变大小,但不超过3
。将x
的类型更改为double(:3 x 1)
,将cb
的类型更改为double(:3 x :216)
。
现在,您可以按照与以前相同的步骤生成代码。euclidean.c
中生成的 C 代码的函数签名现在为:
void euclidean(const double x_data[], const int x_size[1], const double cb_data[], const int cb_size[2], double y_min_data[], int y_min_size[1], double y_max_data[], int y_max_size[1], double idx[2], double distance[2])
x_data
、cb_data
、y_min_data
和 y_max_data
对应于原始 MATLAB 函数中的输入参数 x
和 cb
以及输出参数 y_min
和 y_max
。现在,C 函数接受四个额外的输入参数,即 x_size
、cb_size
、y_min_size
和 y_max_size
,它们在运行时指定 x_data
、cb_data
、y_min_data
和 y_max_data
的大小。接下来的步骤
目的 | 更多信息 |
---|---|
了解对 MATLAB 内置函数和工具箱函数、类和 System object 的代码生成支持 | |
生成 C++ 代码 | |
生成并修改示例 C 主函数,并使用它来编译 C 可执行程序 | |
将生成的文件打包为压缩文件 | |
优化所生成的代码的执行速度或内存使用量。 | |
将您的自定义 C/C++ 代码集成到生成的代码中 | |
了解代码生成报告 | Interactively Trace Between MATLAB Code and Generated C/C++ Code (Embedded Coder) |