从生成的代码中调用自定义 C/C++ 代码
在 MATLAB® 代码中,您可以直接调用外部 C/C++ 代码,也称为自定义代码或原有代码。要调用 C/C++ 函数,请使用 coder.ceval。代码生成器将您的 C/C++ 代码集成到从 MATLAB 生成的 C/C++ 代码中。当您要将生成的代码与外部库、优化的代码或在 C/C++ 中开发的目标文件结合使用时,请集成代码。当外部代码使用 MATLAB 未定义或不能识别的变量类型时,请将 coder.opaque 函数与 coder.ceval 结合使用。要保留某些标识符名称,以便在要与生成的代码集成的自定义 C/C++ 代码中使用,请使用 coder.reservedName 函数。
以下是外部代码集成的一些主要工作流。有关更多示例,请参阅 coder.ceval 参考页。
注意
使用 coder.ceval,您可以不受限制地访问外部代码。在代码中误用这些函数或者代码中的错误可能会导致 MATLAB 不稳定并停止工作。要调试代码并分析编译中的错误消息,请查看代码生成报告中的编译日志选项卡。
coder.ceval 只能在 MATLAB 代码中用于代码生成。在未编译的 MATLAB 代码中,coder.ceval 将生成错误。要确定 MATLAB 函数是否在 MATLAB 中执行,请使用 coder.target。如果函数在 MATLAB 中执行,请调用 MATLAB 版本的 C/C++ 函数。
调用 C 代码
此示例说明如何使用 coder.ceval 将简单的 C 函数与 MATLAB® 代码集成。以 MATLAB 函数 mathOps 为例:
function [added, multed] = mathOps(in1, in2) added = in1+in2; multed = in1*in2; end
对于此示例,假设您要使用外部 C 代码实现加法运算。请考虑在 adder.c 文件中实现的 C 函数 adder:
#include <stdio.h>
#include <stdlib.h>
#include "adder.h"
double adder(double in1, double in2)
{
return in1 + in2;
}
要将 adder 与 MATLAB 代码集成,需要具有包含函数原型的头文件。请参阅文件 adder.h:
double adder(double in1, double in2);
使用 coder.ceval 命令在 mathOpsIntegrated.m 中调用 C 函数。使用 coder.cinclude 包含头文件。
function [added, multed] = mathOpsIntegrated(in1, in2) %#codegen % for code generation, preinitialize the output variable % data type, size, and complexity added = 0; % generate an include in the C code coder.cinclude('adder.h'); % evaluate the C function added = coder.ceval('adder', in1, in2); multed = in1*in2; end
要生成代码,请使用 codegen 命令。将源文件 adder.c 指定为输入。要测试 C 代码,请执行 MEX 函数并检查输出结果。
codegen mathOpsIntegrated -args {1, 2} adder.c [test1, test2] = mathOpsIntegrated_mex(10, 20)
Code generation successful.
test1 =
30
test2 =
200
从一个 C 函数返回多个值
C 语言限制函数返回多个输出。函数只能返回单个标量值。您可以使用 MATLAB 函数 coder.ref、coder.rref 和 coder.wref 从一个外部 C/C++ 函数返回多个输出。
例如,假设您编写 MATLAB 函数 foo,该函数接受 x 和 y 两个输入并返回 a、b 和 c 三个输出。在 MATLAB 中,您可以按如下方式调用此函数:
[a,b,c] = foo(x,y)
如果将 foo 重写为 C 函数,则不能通过一个 return 语句返回三个单独的值 a、b 和 c。在这种情况下,请创建一个具有多个指针类型参量的 C 函数,并按引用传递输出参数。例如:
void foo(double x,double y,double *a,double *b,double *c)
然后,您可以使用 coder.ceval 函数从 MATLAB 函数调用该 C 函数。
coder.ceval('foo',x,y,coder.ref(a),coder.ref(b),coder.ref(c));如果您的外部 C 函数仅读写按按引用传递的内存,则可以使用 coder.wref 或 coder.rref 函数而不是 coder.ref。在某些情况下,这些函数可以进一步优化生成的代码。当您使用 coder.wref(arg) 按引用传递 arg 时,外部 C/C++ 函数必须对 arg 引用的内存进行完全初始化。
按引用传递数据
此示例说明如何按引用向外部 C 函数传递数据或传递来自外部 C 函数的数据。
按引用传递是 C/C++ 代码集成的一种重要方法。按引用传递数据时,程序不需要将数据从一个函数复制到另一个函数。按值传递时,C 代码只能返回单个标量变量。按引用传递时,C 代码可以返回多个变量,包括数组。
以 MATLAB 函数 adderRef 为例。此函数使用外部 C 代码将两个数组相加。coder.rref 和 coder.wref 命令指示代码生成器将指针传递给数组,而不是复制它们。
function out = adderRef(in1, in2) %#codegen out = zeros(size(in1)); % the input numel(in1) is converted to integer type % to match the cAdd function signature coder.ceval('cAdd', coder.rref(in1), coder.rref(in2), coder.wref(out), int32(numel(in1)) ); end
C 代码 cAdd.c 使用线性索引来访问数组的元素:
#include <stdio.h>
#include <stdlib.h>
#include "cAdd.h"
void cAdd(const double* in1, const double* in2, double* out, int numel)
{
int i;
for (i=0; i<numel; i++) {
out[i] = in1[i] + in2[i];
}
}
要编译 C 代码,您必须提供带有函数签名的头文件 cAdd.h:
void cAdd(const double* in1, const double* in2, double* out, int numel);
通过生成 MEX 函数并将其输出与 MATLAB 中的加法运算的输出进行比较来测试 C 代码。
A = rand(2,2)+1; B = rand(2,2)+10; codegen adderRef -args {A, B} cAdd.c cAdd.h -report if (adderRef_mex(A,B) - (A+B) == 0) fprintf(['\n' 'adderRef was successful.']); end
Code generation successful: To view the report, open('codegen/mex/adderRef/html/report.mldatx')
adderRef was successful.集成使用自定义数据类型的外部代码
此示例说明如何调用使用了非 MATLAB® 定义的原生数据类型的 C 函数。
例如,如果您的 C 代码对 C 'FILE *' 类型执行文件输入或输出,则 MATLAB 中没有对应的类型。要在 MATLAB 代码中与此数据类型进行交互,必须使用 coder.opaque 函数对其进行初始化。对于结构体类型,可以使用 coder.cstructname。
例如,假设有 MATLAB 函数 addCTypes.m。此函数使用其输入类型在外部代码中定义的 coder.ceval。函数 coder.opaque 在 MATLAB 中对该类型进行初始化。
function [out] = addCTypes(a,b) %#codegen % generate include statements for header files coder.cinclude('MyStruct.h'); coder.cinclude('createStruct.h'); coder.cinclude('useStruct.h'); % initialize variables before use in = coder.opaque('MyStruct'); out = 0; % call C functions in = coder.ceval('createStruct',a,b); out = coder.ceval('useStruct',in); end
createStruct 函数输出 C 结构体类型:
#include <stdio.h>
#include <stdlib.h>
#include "MyStruct.h"
#include "createStruct.h"
struct MyStruct createStruct(double a, double b) {
struct MyStruct out;
out.p1 = a;
out.p2 = b;
return out;
}
useStruct 函数对该 C 类型执行操作:
#include "MyStruct.h"
#include "useStruct.h"
double useStruct(struct MyStruct in) {
return in.p1 + in.p2;
}
要生成代码,请将源 (.c) 文件指定为输入:
codegen addCTypes -args {1,2} -report createStruct.c useStruct.c
Code generation successful: To view the report, open('codegen/mex/addCTypes/html/report.mldatx')
集成使用指针、结构体和数组的外部代码
此示例说明如何将对 C 样式数组执行运算的外部代码与 MATLAB® 代码集成。外部代码计算数组数据的和。您可以自定义代码以更改输入数据或计算。
此示例说明如何合并外部代码集成功能的多个不同元素。例如,您可以:
使用
coder.cstructname对接外部结构体类型使用
coder.opaque对接外部指针类型使用
coder.ceval执行外部代码使用
coder.ref按引用将数据传递到外部代码
浏览集成后的代码
extSum 函数使用外部 C 代码对 32 位整数数组执行求和运算。数组大小由用户输入控制。
function x = extSum(u) %#codegen % set bounds on input type to use static memory allocation u = int32(u); assert(0 < u && u < 101); % initialize an array temparray = int32(1):u; % declare an external structure and use it s = makeStruct(u); x = callExtCode(s, temparray);
为了简化生成的代码,请对数组大小设置限制。限制可防止在生成的代码中使用动态内存分配。
函数 makeStruct 声明一种 MATLAB 结构体类型,并使用 coder.opaque 将其中一个字段初始化为指针类型。与此定义对应的 C 结构体包含在一个头文件中,您通过使用 coder.cstructname 函数中的 HeaderFile 参数提供该头文件。C 结构体类型提供了整数数组的简单表示。
function s = makeStruct(u) % create structure type based on external header definition s.numel = u; s.vals = coder.opaque('int32_T *','NULL'); coder.cstructname(s,'myArrayType','extern','HeaderFile','arrayCode.h');
在完全初始化外部结构体类型后,您可以将其作为输入传递给 callExtCode 函数中的外部代码。此函数对数组进行初始化,调用对数组执行的运算以返回单个输出,然后释放经过初始化的内存。
function x = callExtCode(s, temparray) % declare output type x = int32(0); % declare external source file coder.updateBuildInfo('addSourceFiles','arrayCode.c'); % call c code coder.ceval('arrayInit',coder.ref(s),coder.ref(temparray)); x = coder.ceval('arraySum',coder.ref(s)); coder.ceval('arrayDest',coder.ref(s));
该函数使用 coder.updateBuildInfo 将 .c 文件提供给代码生成器。
生成 MEX 函数
要生成可以在 MATLAB 中运行和测试的 MEX 函数,请输入:
codegen extSum -args {10}
Code generation successful.
测试 MEX 函数。输入:
extSum_mex(10)
ans = int32 55
包含在文件 arrayCode.c 和 arrayCode.h 中的外部 C 代码使用自定义类型定义 int32_T。生成的 MEX 代码将生成并使用此自定义类型定义。如果要生成使用此自定义数据类型的独立(lib、dll 或 exe)代码,您可以修改配置对象的 DataTypeReplacement 属性。请参阅将 MATLAB 类型映射到生成的代码中的类型。
另请参阅
codegen | coder.wref | coder.ceval | coder.rref | coder.ref | coder.cinclude | coder.cstructname | coder.opaque | coder.reservedName