从生成的代码中调用自定义 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