从生成的代码中调用自定义 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 不稳定并停止工作。要调试代码并分析编译中的错误消息,请查看代码生成报告中的 Build Logs 选项卡。
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
属性。请参阅Mapping MATLAB Types to Types in Generated Code。
另请参阅
codegen
| coder.wref
| coder.ceval
| coder.rref
| coder.ref
| coder.cinclude
| coder.cstructname
| coder.opaque
| coder.reservedName