主要内容

本页采用了机器翻译。点击此处可查看最新英文版本。

将 C++ 结构传递给已部署的 MATLAB 函数

自 R2024b 起

此示例说明如何将 C++ 结构传递给部署在 C++ 应用程序中的 MATLAB® 函数。Windows®、Linux®macOS 系统支持此工作流。

要将 C++ 结构传递给 MATLAB 函数,在应用程序代码中,必须以 IN_PROCESS 模式启动 MATLAB Runtime。您需要使用 USING_TYPE_WITH_MATLAB 宏来告知 MATLAB 有关自定义 C++ 类型,以确保在函数调用期间正确识别和处理。此外,在传递这些结构时,您必须在 C++ 代码中使用 matlab::cpplib::MATLABLibrary::feval 方法来评估和执行 MATLAB 函数。

前提条件

  • 创建一个对 MATLAB 搜索路径可见的新工作文件夹。此示例使用名为 work 的文件夹。

  • 验证您是否已设置 C++ 开发环境。有关详细信息,请参阅设置 C++开发环境。本示例使用 MATLAB 作为 C++ 开发环境。因此,通过在 MATLAB 命令提示符下键入 mbuild -setup C++ 来验证您是否已安装 C++ 编译器。

  • 验证您是否已满足所有 MATLAB Compiler SDK™ C++ 目标要求。有关详细信息,请参阅MATLABCompiler SDK C++ 目标要求

  • 最终用户必须安装 MATLAB Runtime 才能运行应用程序。有关详细信息,请参阅下载并安装 MATLAB Runtime

    出于测试目的,您可以在运行 C++ 应用程序时使用 MATLAB 安装而不是 MATLAB Runtime

创建包含命名空间和结构定义的 C++ 头文件

创建一个名为 cppstruct.hpp 的头文件,其中包含要传递给已部署的 MATLAB 函数的数据的命名空间和结构定义。

#include <vector>
#include <string>
#include <map>

// Define a namespace for the struct definitions
namespace cppstruct {

    // Define a struct for the input data
    struct InputStruct {
        std::vector<double> temperatures;
        std::vector<double> pressures;
    };

    // Define a struct for the statistical results of each field
    struct FieldStats {
        double mean;
        double std;
        double max;
    };

    // Define a struct for the output data
    struct OutputStruct {
        FieldStats temperatures;
        FieldStats pressures;
    };

}

cppstruct.hpp 头文件定义了一个命名空间 cppstruct,它包含三个结构:InputStructFieldStatsOutputStruct

  • InputStruct 保存温度和压力数据向量。

  • FieldStats 存储字段的以下统计结果:平均值、标准差和最大值。

  • OutputStruct 是一个嵌套结构,包含温度和压力的 FieldStats

生成 MATLAB 接口到 C++ 头文件

使用 clibgen.buildInterface 函数为名为 cppstruct.hpp 的 C++ 头文件生成一个 MATLAB 接口。在这种特殊情况下,我们选择将接口命名为 data,但在其他情况下,您可以使用不同的名称。

clibgen.buildInterface("cppstruct.hpp", InterfaceName="data")

这将创建一个名为 data 的文件夹并生成一个名为 dataInterface.dll 的 DLL。clibgen.buildInterface 函数遵循将单词 Interface 追加到您提供的接口名称的约定。

将接口添加到 MATLAB 路径

要在 MATLAB 代码中使用 C++ 结构,请将接口文件夹添加到 MATLAB 路径。

addpath("P:\MATLAB\work\data")

创建 MATLAB 函数

使用以下代码创建一个名为 analyzeData.m 的 MATLAB 文件:

function outputStruct = analyzeData(inputStruct)
% analyzeData Analyzes numeric fields in a C++ struct and returns
% statistical measures.
%
% This function takes 'inputStruct' as input, which is a MATLAB
% representation of a C++ struct. This representation is generated using
% the clibgen.buildInterface function. The function performs statistical
% analysis on each numeric field within the struct and returns the results
% in a new struct 'outputStruct'. The analyses include computing the mean,
% standard deviation, and maximum value for each numeric field.
%
% Inputs:
%   inputStruct - A MATLAB representation of a C++ struct
%   (clib.data.cppstruct.InputStruct) that has temperature and pressure
%   data. It contains the fields: 
%   - temperatures: a clib.array.data.Double array of temperature values 
%   - pressures: a clib.array.data.Double array of pressure values
%
% Outputs:
%   outputStruct - A MATLAB representation of a C++ struct
%   (clib.data.cppstruct.OutputStruct) with the same fields as
%   'inputStruct'. For each numerical array in 'inputStruct', the
%   corresponding field in 'outputStruct' is a struct containing:
%   - mean: Mean value of the numerical array 
%   - std: Standard deviation of the numerical array 
%   - max: Maximum value of the numerical array


arguments (Input)
    inputStruct (1,1) clib.data.cppstruct.InputStruct
end

arguments (Output)
    outputStruct (1,1) clib.data.cppstruct.OutputStruct
end

% Initialize outputStruct
outputStruct = clib.data.cppstruct.OutputStruct;

% Perform analysis on 'temperatures' field
if isa(inputStruct.temperatures, 'clib.array.data.Double')
    % Cast C++ clib.array.data.Double array to MATLAB double array
    doubleTemperatures = double(inputStruct.temperatures);
    
    % Calculate mean
    outputStruct.temperatures.mean = mean(doubleTemperatures);
    
    % Calculate standard deviation
    outputStruct.temperatures.std = std(doubleTemperatures);

    % Calculate max value
    outputStruct.temperatures.max = max(doubleTemperatures);
else
    warning('Field temperatures is not numeric and was skipped.');
end

% Perform analysis on 'pressures' field
if isa(inputStruct.pressures, 'clib.array.data.Double')
    % Cast C++ clib.array.data.Double array to MATLAB double array
    doublePressures = double(inputStruct.pressures);
    
    % Calculate mean
    outputStruct.pressures.mean = mean(doublePressures);
    
    % Calculate standard deviation
    outputStruct.pressures.std = std(doublePressures);

    % Calculate max value
    outputStruct.pressures.max = max(doublePressures);
else
    warning('Field pressures is not numeric and was skipped.');
end

end

要在 MATLAB 函数中使用 C++ 结构,您需要在函数的 arguments 模块中指定参量定义。这些定义表明将使用 cppstruct.hpp 头文件中定义的 C++ 结构。首先,确保包含生成的 MATLAB 接口文件的文件夹已添加到 MATLAB 路径。在头文件中定义的结构在 MATLAB 中使用命名约定 clib.<interface_name>.<namespace>.<structure_name> 进行访问。例如,在这种情况下,使用 clib.data.cppstruct.InputStruct 作为输入结构,使用 clib.data.cppstruct.OutputStruct 作为输出结构。

有关数据类型映射的详细信息,请参阅C++ to MATLAB Data Type Mapping

在命令提示符下测试 MATLAB 函数。

input = clib.data.cppstruct.InputStruct;
input.temperatures = [72, 75, 69, 68, 70];
input.pressures = [30, 29.5, 30.2, 29.9, 30.1];
output = analyzeData(input)
disp("Temperatures:")
disp(output.temperatures)
disp("Pressures:")
disp(output.pressures)
output = 
  OutputStruct with properties:

    temperatures: [1×1 clib.data.cppstruct.FieldStats]
       pressures: [1×1 clib.data.cppstruct.FieldStats]
Temperatures:
  FieldStats with properties:

    mean: 70.8000
     std: 2.7749
     max: 75
Pressures:
  FieldStats with properties:

    mean: 29.9400
     std: 0.2702
     max: 30.2000

使用 compiler.build.cppSharedLibrary 封装 MATLAB 函数

使用 compiler.build.cppSharedLibrary 函数从 MATLAB 函数创建代码存档(.ctf 文件)。

buildResults = compiler.build.cppSharedLibrary("analyzeData.m", ...
    OutputDir=".\output", Verbose="on",...
    AdditionalFiles="P:\MATLAB\work\data\dataInterface.dll");

必须使用 dataInterface.dll 名称-值对将接口库 AdditionalFiles 添加为依赖文件。

该函数生成一套文件(如下所列),并将它们放在指定的 output 目录中。其中,集成过程中使用的关键文件是包含 MATLAB 代码的代码存档(.ctf 文件)。有关其他文件的信息,请参阅打包 MATLAB 函数后生成的文件

P:\MATLAB\WORK\OUTPUT
│   GettingStarted.html
│   includedSupportPackages.txt
│   mccExcludedFiles.log
│   readme.txt
│   requiredMCRProducts.txt
│   unresolvedSymbols.txt
│
└───v2
    └───generic_interface
            analyzeData.ctf
            analyzeDatav2.hpp
            readme.txt

注意

analyzeDatav2.hpp 头文件通常用于处理强类型接口,在此上下文中生成但未使用。

注意

生成的工件不包括 MATLAB Runtime 或安装程序。要使用 buildResults 对象创建安装程序,请参阅 compiler.package.installer

MATLAB 代码存档集成到 C++ 应用程序中

您可以在首选的 C++ 开发环境中完成集成过程,包括 MATLAB 或 Windows 上的 Microsoft® Visual Studio® 等替代方案。但是,此示例使用 MATLAB 作为 C++ 开发环境。有关详细信息,请参阅设置 C++开发环境

要将生成的 MATLAB 代码存档(.ctf 文件)集成到 C++ 应用程序中,请遵循以下准则:

  • 使用 #include 指令将包含结构定义的 C++ 头文件(.hpp 文件)合并到您的 C++ 应用程序代码中。

  • 确保代码存档(.ctf 文件)位于 C++ 可执行文件可以访问的位置。

完成集成步骤需要熟练的 C++ 技能来编写应用程序代码。编写自己的应用程序时,可以使用以下示例 C++ 应用程序代码作为指南。

  1. 在此示例的 work 文件夹中,创建一个名为 PassCppStructConsoleApp.cpp 的新文件,并包含以下代码。

     PassCppStructConsoleApp.cpp

    IN_PROCESS 模式

    在应用程序代码中,您必须以 IN_PROCESS 模式启动 MATLAB Runtime 才能将 C++ 结构传递给 MATLAB 函数。

    USING_TYPE_WITH_MATLAB

    USING_TYPE_WITH_MATLAB 宏用于告知 MATLAB 在集成中将使用的自定义 C++ 类型。该宏的一般形式为 USING_TYPE_WITH_MATLAB(namespace::structure_name, "interface_name"),其中 namespace::structure_name 是 C++ 结构的完全限定名称,interface_name 是为 MATLAB 定义的接口的名称。此设置确保 MATLAB 在函数调用期间正确识别和处理这些结构。例如,在提供的代码中,宏用于将 cppstruct::OutputStructcppstruct::InputStructcppstruct::FieldStats 类型映射到名为 data 接口。

    matlab::cpplib::MATLABLibrary::feval 方法

    使用强类型接口时,您可以在应用程序代码中包含生成的头文件(.hpp 文件),这样您就可以从 C++ 代码中直接调用(.ctf 文件)中定义的 MATLAB 函数。但是,将 C++ 结构传递给已部署的 MATLAB 函数时,您不能直接调用这些函数。相反,您必须在 C++ 代码中使用 matlab::cpplib::MATLABLibrary::feval 方法来评估和执行 MATLAB 函数。

  2. 通过在 MATLAB 命令提示符下执行 mbuild 函数来编译和链接应用程序。

    mbuild -v PassCppStructConsoleApp.cpp -outdir output\bin

Visual Studio

如果您在集成阶段使用 Visual Studio,请按照设置 Microsoft Visual Studio 进行 C++ 开发(仅限 Windows)。此外,您需要进行一些更改以确保您的调试版本使用与 MATLAB 相同的 C/C++ 运行时库。要做到这一点:

  1. 打开 Visual Studio 并在 Solution Explorer 中导航到您的工程。

  2. 右键点击您的工程名称并从上下文菜单中选择 Properties

  3. 在属性窗口中,导航到 Configuration Properties > C/C++ > Preprocessor

    Preprocessor Definitions 列表中删除 _DEBUG

  4. 导航到 Configuration Properties > C/C++ > Code Generation。将 Runtime Library 设置更改为 Multi-threaded DLL (/MD)

处理代码存档(.ctf 文件)

为确保您的 C++ 应用程序可以访问包含 MATLAB 代码的代码存档(.ctf 文件),请将该文件放置在可执行文件可访问的位置。对于这个示例,我们将通过在 MATLAB 桌面环境中设置 CPPSHARED_BASE_CTF_PATH 环境变量来实现这一点。

setenv("CPPSHARED_BASE_CTF_PATH","P:\MATLAB\work\output\v2\generic_interface")

如果您使用的是 Visual Studio,请参阅在 Visual Studio 中设置环境变量

有关代码存档(.ctf 文件)放置选项的完整列表,请参阅代码存档(.ctf 文件)的放置

运行 C++ 应用程序

为了测试目的,您可以从 MATLAB 命令提示符运行该应用程序。这不需要安装 MATLAB Runtime

!output\bin\PassCppStructConsoleApp.exe
Executing MATLAB function ...
Temperatures - Mean: 70.8000, Std: 2.7749, Max: 75.0000
Pressures - Mean: 29.9400, Std: 0.2702, Max: 30.2000

另请参阅

| | |

主题