Main Content

通过命令行生成 C 代码

在本教程中,您将使用 MATLAB® Coder™codegen 命令为 MATLAB 函数生成静态 C 库。首先生成只能接受具有固定预分配大小的输入的 C 代码。然后生成可以接受许多不同大小的输入的 C 代码。

您还可以使用 MATLAB Coder 生成代码。有关此工作流的教程,请参阅使用 MATLAB Coder 生成 C 代码

教程文件:欧几里德距离

打开此示例以获取本教程的文件。

教程文件的描述

本教程使用 euclidean_data.mateuclidean.mtest.mbuild_lib_fixed.mbuild_lib_variable.m 文件。

  • MATLAB 数据文件 euclidean_data.mat 包含两段数据:三维欧几里德空间中的一个点以及三维欧几里德空间中的一组其他点。更具体地说:

    • x 是一个 3×1 列向量,表示三维欧几里德空间中的一个点。

    • cb 是一个 3×216 数组。cb 中的每列都表示三维欧几里德空间中的一个点。

  • MATLAB 文件 euclidean.m 包含 euclidean 函数,该函数在本示例中实现核心算法。该函数接受 xcb 作为输入。它计算 xcb 中每个点之间的欧几里德距离,并返回以下量:

    • 列向量 y_min,它等于 cb 中表示与 x 距离最近的点的列。

    • 列向量 y_max,它等于 cb 中表示与 x 距离最远的点的列。

    • 二维向量 idx,它包含 cb 中向量 y_miny_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_miny_maxidxdistance。然后,脚本在命令行中显示计算出的量。

    加载 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))]);
  • 编译脚本 build_lib_fixed.mbuild_lib_variable.m 包含的命令可从您的 MATLAB 代码生成静态 C 库,这两个库分别接受固定大小和可变大小输入。这些脚本的内容显示在本教程后面有关生成 C 代码的部分中。

提示

您可以使用 MATLAB Coder 从 MATLAB 函数生成代码。不支持从 MATLAB 脚本生成代码。

请使用测试脚本将预处理和后处理步骤与实现核心算法的函数分隔开。这种做法使您能够轻松地重用您的算法。您需要为实现核心算法的 MATLAB 函数生成代码。不需要为测试脚本生成代码。

MATLAB 函数生成 C 代码

运行原始 MATLAB 代码

在 MATLAB 中运行测试脚本 test.m。输出显示 yidxdistance

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 编辑器中的代码分析器会在您输入代码时持续检查代码。它会报告问题,并提出修改建议,以最大程度地提高性能和可维护性。代码生成就绪工具会筛查 MATLAB 代码中是否存在代码生成不支持的功能和函数。

C/C++ 代码生成支持的某些 MATLAB 内置函数和工具箱函数、类以及 System object 有特定的代码生成限制。这些限制和相关使用说明列在其对应参考页的扩展功能部分。有关详细信息,请参阅 C/C++ 代码生成支持的函数和对象

  1. 在 MATLAB 编辑器中打开 euclidean.m。MATLAB 编辑器右上角的代码分析器消息指示标记为绿色。分析器未在代码中检测到错误、警告或改进机会。

  2. 在函数声明后面添加 %#codegen 指令:

    function [y,idx,distance] = euclidean(x,cb) %#codegen
    %#codegen 指令提示代码分析器识别特定于代码生成的警告和错误。

    代码分析器消息指示标记变为红色,表示它检测到代码生成问题。

    Code Analyzer window containing sample code, showing red indicator and underlining corresponding to detected code generation issues

  3. 要查看警告消息,请将光标移到带下划线的代码片段上。警告指示,代码生成要求先对变量 idxdistance 进行完全定义,然后才可以对它们进行下标索引。出现这些警告是因为代码生成器必须在这些变量在代码中首次出现时确定其大小。要解决此问题,请使用 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));

    代码分析器消息指示标记再次变为绿色,表示它没有再检测到任何代码生成问题。

    Code Analyzer window containing sample code, showing green indicator

    有关使用代码分析器的详细信息,请参阅使用代码分析器检查代码中的错误和警告

  4. 保存文件。

  5. 要运行代码生成就绪工具,请从 MATLAB 命令行调用 coder.screener 函数。

    coder.screener('euclidean')

    该工具不会检测 euclidean 的任何代码生成问题。有关详细信息,请参阅代码生成就绪工具

    注意

    代码分析器和代码生成就绪工具可能无法检测到所有代码生成问题。消除这两个工具检测到的错误或警告后,使用 MATLAB Coder 生成代码以确定您的 MATLAB 代码是否还存在其他合规性问题。

现在您即可使用 MATLAB Coder 编译您的代码。此处,编译指从您的 MATLAB 代码生成 C/C++ 代码。

注意

编译 MATLAB 代码指从 MATLAB 代码生成 C/C++ 代码。在其他情况下,“编译”可能指 C/C++ 编译器的操作。

定义输入类型

由于 C 使用静态定型,因此在代码生成时(也称为编译时),代码生成器必须确定 MATLAB 文件中所有变量的类、大小和复/实性。因此,在为文件生成代码时,必须指定入口函数的所有输入参量的属性。入口函数是顶层 MATLAB 函数,您可以从中生成代码。

当您使用 codegen 命令生成代码时,请使用 -args 选项指定入口函数的示例输入参数。代码生成器使用这些信息来确定输入参量的属性。

在下一步中,您将使用 codegen 命令从入口函数 euclidean 生成 MEX 文件。

检查运行时问题

您从入口函数生成 MEX 函数。MEX 函数是可从 MATLAB 内部调用的生成的代码。运行该 MEX 函数,检查生成的 MEX 函数和原始的 MATLAB 函数是否具有相同的功能。

执行此步骤是一个很好的做法,因为您可以检测并解决在生成的 C 代码中更难诊断出来的运行时错误。默认情况下,MEX 函数包括内存完整性检查。这些检查执行数组边界和维度检查,还检测为 MATLAB 函数生成的代码中是否存在内存完整性冲突问题。有关详细信息,请参阅Control Run-Time Checks

为了将 MATLAB 代码转换为高效的 C/C++ 源代码,代码生成器引入了优化,在某些情况下,这会导致生成的代码与原始源代码在行为上有所不同。请参阅生成的代码和 MATLAB 代码之间的差异

  1. 使用 codegen 命令为 euclidean.m 生成 MEX 文件。要验证 MEX 函数,请运行测试脚本 test,并将调用 MATLAB 函数 euclidean 替换为调用生成的 MEX 函数。

    % Load the test data
    load euclidean_data.mat
    % Generate code for euclidean.m with codegen. Use the test data as example input.
    codegen euclidean.m -args {x,cb} -test test

    • 默认情况下,codegen 在当前文件夹中生成名为 euclidean_mex 的 MEX 函数。

    • 您可以使用 -args 选项指定入口函数 euclidean 的示例输入参数。代码生成器使用这些信息来确定输入参量的属性。

    • 您使用 -test 选项运行测试文件 test.m。此选项将测试文件中对 euclidean 的调用替换为对 euclidean_mex 的调用。

    输出为:

    Running test file: 'test' with MEX function 'euclidean_mex'.
    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 函数生成的输出相匹配,并验证 MEX 函数。现在,您可以为 euclidean 生成独立的 C 代码。

注意

在从您的 MATLAB 代码生成独立的 C/C++ 代码之前,请生成 MEX 函数。运行生成的 MEX 函数,并确保它具有与您的 MATLAB 函数相同的运行时行为。如果生成的 MEX 函数的执行结果不同于 MATLAB 的结果,或者出错,您必须先修复这些问题,然后生成独立的代码。否则,您生成的独立代码可能不可靠并且具有未定义的行为。

生成 C 代码

编译脚本 build_lib_fixed.m 包含用于为 euclidean.m 生成代码的命令。

% Load the test data
load euclidean_data.mat
% Generate code for euclidean.m with codegen. Use the test data as example input.
codegen -report -config:lib euclidean.m -args {x, cb}
请注意:

  • codegen 读取文件 euclidean.m,并将 MATLAB 代码转换为 C 代码。

  • -report 选项指示 codegen 生成代码生成报告,您可使用该报告调试代码生成问题,并验证您的 MATLAB 代码是否适用于代码生成。

  • -config:lib 选项指示 codegen 生成静态 C 库,而不是生成默认 MEX 函数。

  • -args 选项指示 codegen 使用示例输入参数 xcb 的类、大小和复/实性为 euclidean.m 生成代码。

您可以通过使用适当的选项和 codegen 命令,选择生成 MEX 函数或其他 C/C++ 编译类型,而不是生成 C 静态库。有关各种代码生成选项的详细信息,请参阅 codegen

  1. 运行编译脚本。

    MATLAB 会处理编译文件,并输出以下消息:

    Code generation successful: View report.
    代码生成器在 work\codegen\lib\euclidean 中生成独立的 C 静态库 euclidean。此处,work 是包含您的教程文件的文件夹。

  2. 要在报告查看器中查看代码生成报告,请点击查看报告

    如果代码生成器在代码生成过程中检测到错误或警告,报告将说明问题并提供有问题的 MATLAB 代码的链接。请参阅Code Generation Reports

提示

在命令行使用编译脚本生成代码。编译脚本自动执行您在命令行重复执行的一系列 MATLAB 命令,可帮助您节省时间和消除输入错误。

将生成的 C 代码与原始 MATLAB 代码进行比较

要将生成的 C 代码与原始 MATLAB 代码进行比较,请在 MATLAB 编辑器中打开 C 文件 euclidean.ceuclidean.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 代码中的输入 xx 的大小是 3,它对应于您在为 MATLAB 生成代码时使用的示例输入的总大小 (3×1)。

    const double cb[648] 对应于您的 MATLAB 代码中的输入 cbcb 的大小是 648,它对应于您在为 MATLAB 生成代码时使用的示例输入的总大小 (3×216)。在本例中,生成的代码使用一维数组来表示 MATLAB 代码中的二维数组。

    生成的代码有四个额外的输入参量:数组 y_miny_maxidxdistance。这些数组用于返回输出值。它们对应于原始 MATLAB 代码中的输出参量 y_miny_maxidxdistance

  • 代码生成器将保留您的函数名称和注释。如果可能,代码生成器会保留您的变量名称。

    注意

    如果您的 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 代码中的 xcb 的维度具有以下属性:

  • xcb 的第一个维度的大小为可变大小,但不超过 3

  • x 的第二个维度具有固定大小,其值为 1

  • cb 的第二个维度的大小为可变大小,但不超过 216

要指定这些输入属性,请使用 coder.typeof 函数。coder.typeof(A,B,1) 指定一个可变大小的输入,其类和复/实性与 A 相同,其上限由大小向量 B 的对应元素给出。使用编译脚本 build_lib_variable.m,该脚本使用 coder.typeof 在生成的 C 库中指定可变大小输入的属性。

% Load the test data
load euclidean_data.mat

% Use coder.typeof to specify variable-size inputs
eg_x=coder.typeof(x,[3 1],1);
eg_cb=coder.typeof(cb,[3 216],1);

% Generate code for euclidean.m using coder.typeof to specify
% upper bounds for the example inputs
codegen -report -config:lib euclidean.m -args {eg_x,eg_cb}

现在,您可以按照与以前相同的步骤生成代码。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_datacb_datay_min_datay_max_data 对应于原始 MATLAB 函数中的输入参量 xcb 以及输出参量 y_miny_max。现在,C 函数接受四个额外的输入参量,即 x_sizecb_sizey_min_sizey_max_size,它们在运行时指定 x_datacb_datay_min_datay_max_data 的大小。

接下来的步骤

目的更多信息

了解对 MATLAB 内置函数和工具箱函数、类和 System object 的代码生成支持

C/C++ 代码生成支持的函数和对象

生成 C++ 代码

C++ 代码生成

以交互方式创建和编辑输入类型

Create and Edit Input Types by Using the Coder Type Editor

生成并修改示例 C 主函数,并使用它来编译 C 可执行程序

在应用程序中使用示例 C 主函数

将生成的文件打包为压缩文件

Package Code for Other Development Environments

优化所生成的代码的执行速度或内存使用量。

优化策略

将您的自定义 C/C++ 代码集成到生成的代码中

从生成的代码中调用自定义 C/C++ 代码

了解代码生成报告

Code Generation Reports

Interactively Trace Between MATLAB Code and Generated C/C++ Code (Embedded Coder)

另请参阅

|