在大多数情况下,当您为MATLAB生成代码时®函数接受或返回数组时,生成的C/ c++函数接口包含数组。要使用生成的函数接口,请了解如何定义和构造生成的C/ c++数组。尤其要学会使用emxArray
生成以表示动态分配的数组的数据结构。
在生成C/ c++代码时,会创建一个示例主文件,演示如何在生成的函数代码中使用数组。您可以使用示例main作为自己应用程序的模板或起点。
代码生成器生成C/ c++数组定义,这些定义取决于数组元素类型以及数组使用静态还是动态内存分配。数组的两种内存分配需要两种不同的实现:
对于大小限制在预定义阈值内的数组,生成的C/ c++定义由一个指向内存的指针和一个存储数组元素总数(数组大小)的整数组成。这个数组的内存来自程序堆栈,是静态分配的。
对于在编译时大小未知且未绑定的数组,或其绑定超过预定义的阈值的数组,生成的C/ c++定义由一个称为emxArray
.当一个emxArray
时,根据当前数组大小设置中间存储边界。在程序执行期间,当超过中间存储边界时,生成的代码从堆中占用额外的内存空间,并将其添加到emxArray
存储。这个数组的内存是动态分配的。
默认情况下,在阈值大小范围内的数组不会在生成的代码中使用动态分配。您也可以禁用动态内存分配,并更改动态内存分配阈值。看到控制可变大小数组的内存分配.
这个表列出了生成代码中数组表示的一些典型情况。
算法描述和数组大小 |
MATLAB函数 |
生成C函数接口 |
---|---|---|
将它们放置到固定大小的1 × 500行向量上。 固定大小,阈值范围内。 |
函数B = create_vec0% # codegenB = 0 (1500);j = 1;为i = 1:50 0如果round(rand) B(1,j) = 1;J = J + 1;结束结束 |
空白create_vec0(双B [500]) |
将1推入到以300个元素为界的可变大小行向量上。 可变大小,阈值范围内。 |
函数B = create_vec% # codegenB = 0 (1,0);coder.varsize (“B”[300], [0 1]);为i = 1:50 0如果round(rand) B = [1 B];结束结束 |
void create_vec(double B_data[], int B_size[2]) |
将1推入到一个以30,000个元素为界的可变大小行向量上。 可变大小,不受阈值限制。 |
函数B = create_vec2% # codegenB = 0 (1,0);coder.varsize (“B”[30000], [0 1]);为i = 1:50 0如果round(rand) B = [1 B];结束结束 |
空白create_vec2 (emxArray_real_T * B) |
创建一个数组,其大小由无界整数输入决定。 在编译时未知且无界。 |
函数y = create_vec3 (n)% # codegeny = int8 ((1, n)); |
void create_vec3(int n, emxArray_int8_T *y) |
emxArray
动态数据结构定义在生成的C/ c++代码中emxArray
数据结构定义取决于它所存储的元素的数据类型。一般定义的形式为:
struct emxArray_{ *data;int *大小;int allocatedSize;int numDimensions;boolean_T canFreeData;};
的定义,<类型>
表示数据类型和<名称>
用于标识的名称emxArray
结构。代码生成器选择<名称>
基于为MEX代码生成定义的类型,如中所列将MATLAB类型映射到生成代码中的类型.
作为一个例子,考虑emxArray
为函数生成的定义create_vec2
.的<名称>
是emxArray_real_T
和<类型>
是双
.
struct emxArray_real_T{双*数据;int *大小;int allocatedSize;int numDimensions;boolean_T canFreeData;};
不寻求预测的条目<类型>
而且<名称>
在代码生成之前。相反,在代码生成完成后,检查文件
来自代码生成报告。myFunction < >
_types.hmyFunction < >
是入口点函数的名称。
生成的代码还可以定义emxArray
结构用类型定义
语句,如在这些例子中。
typedef struct {emxArray_real_T *f1;} cell_wrap_0;类型定义结构{cell_wrap_0 *data;int *大小;int allocatedSize;int numDimensions;boolean_T canFreeData;} emxArray_cell_wrap_0;
该表描述了emxArray
结构字段。
场 | 描述 |
---|---|
<类型> *数据 |
指向类型元素数组的指针<类型> . |
int *大小 |
指向大小向量的指针。size向量的第i个元素存储数组第i维的长度。 |
int allocatedSize |
分配给数组的内存元素的数目。如果数组大小发生变化,生成的代码将根据新的大小重新分配内存。 |
int numDimensions |
大小向量的长度。在不跨越未分配或未使用内存的情况下可以访问的维度数量。 |
boolean_T canFreeData |
指示如何释放内存的布尔标志。只在内部使用
|
emxArray
数据创造和互动emxArray
当您的C/ c++代码中包含数据时,代码生成器将导出一组具有用户友好API的C/ c++助手函数。使用这些函数可以确保正确地初始化和销毁emxArray
数据类型。要使用这些函数,请为生成的头文件插入include语句
在你的C代码中。myFunction < >
_emxAPI.hmyFunction < >
是入口点函数的名称。操作的代码生成器产生的其他函数emxArray
中定义的数据,
,不适于手动使用。myFunction < >
_emxutil.h
的默认生成的示例主文件自由
,dll
,exe
代码包括对emxArray
API函数。示例主代码初始化emxArray
数据为泛型零值。要使用实际的数据输入和值,请修改示例主文件或创建自己的主文件。有关使用main函数的更多信息,请参见使用主函数示例合并生成的代码.
该表显示了导出的列表emxArray
API函数。的初始行数、列数或维数,有些API函数接受emxArray
数据。每个维度都可以根据需要增长以容纳新数据。
emxArray Helper函数 |
描述 |
---|---|
|
创建指向二维的指针emxArray ,其中数据元素初始化为零。为数据分配新内存。 |
|
创建指向n维的指针emxArray ,其中数据元素初始化为零。为数据分配新内存。 |
|
创建指向二维的指针emxArray .使用您提供的数据和内存,并将其封装到emxArray 数据结构。集canFreeData 来假 防止意外释放用户内存。 |
|
创建指向n维的指针emxArray .使用您提供的数据和内存,并将其封装到emxArray 数据结构。集canFreeData 来假 防止意外释放用户内存。 |
|
对象的双指针分配内存emxArray . |
|
对象分配的动态内存emxCreate 或emxInitArray 功能。 |
代码生成器导出emxArray
API函数仅用于作为入口点函数参数的数组或由coder.ceval
.
考虑MATLAB函数myuniquetol
从为可变大小数据生成代码.
函数B = myuniquetol(A, tol)% # codegen一种=(一个);coder.varsize (“B”, [1 100], [0 1]);B = 0 (1,0);k = 1;为我= 2:长度(A)如果abs(A(k) - A(i)) > tol B = [B A(i)];k =我;结束结束
生成的代码myuniquetol
.使用coder.typeof
将输入类型指定为有界的可变大小数组和标量双精度数组。
codegen配置:自由报告myuniquetolarg游戏{编码器。类型of(0,[1 100],[0 1]),coder.typeof(0)}
该声明coder.varsize (“B”,[1 100], [0 1])
指定B
是一个可变大小的数组,其第一个维度固定为1,第二个维度最多可以变化到100个元素。因为数组的最大大小B
在默认阈值大小范围内时,代码生成器为数组使用静态内存分配。
生成的函数接口为:
void myuniquetol(const double A_data[], const int A_size[2], double tol, double B_data[], int B_size[2])
函数接口声明输入参数一个
输出参数B
.A_size
包含的大小一个
.打完电话后myuniquetol
,B_size
包含的大小B
.
使用B_size
确定…元素的数量B
你可以在呼叫后访问myuniquetol
.B_size [0]
包含第一个维度的大小。B_size [1]
包含第二个维度的大小。因此,元素的个数B
是B_size [0] * B_size [1]
.尽管B
有One hundred.
元素在C代码中,只有B_size [0] * B_size [1]
元素包含有效的数据。
这个C main函数演示了如何调用myuniquetol
.
void main(){双A[100], B[100];int A_size[2] = {1,100};int B_size [2];int我;For (i = 0;我< 100;i++) {A[i] = (double)1/i;} myuniquetol(A, A_size, 0.1, B, B_size);}
emxArray
通过使用emxCreate
或emxInitArray
功能的emxCreate
而且emxCreateND
API函数创建一个emxArray
,根据需要从堆中分配新内存。然后您可以使用emxArray
作为生成代码的输入或输出。这个C代码示例演示了如何使用emxCreate
.假设您已经为函数生成了源代码myFunction
它使用数据类型emxArray_uint32_T
.
#include#include #include "myFunction_emxAPI.h" #include "myFunction.h" int main(int argc, char *argv[]){/*创建10 × 10 uint32_T emxArray */ emxArray_uint32_T *pEmx = emxCreate_uint32_T(10,10);/*初始化emxArray内存,如果需要*/ int k = 0;For (k = 0;k < 100;++k) {pEmx->data[k] = (uint32_T) k;} /*这里使用pEmx数组;*/ /*插入调用myFunction */ /*释放pEmx中分配的所有内存*/ /* This DOES free pEmx->data */ emxDestroyArray_uint32_T(pEmx);/*未使用的*/ (void)argc;(空白)argv;返回0; }
在本例中,您知道的初始大小emxArray
.如果不知道数组的大小,比如在使用数组存储输出时,可以为行
而且关口
字段。例如,如果你不知道列数,你可以这样写:
emxArray_uint32_T *pEmx = emxCreate_uint32_T(10,0);
数据结构会根据需要增长以容纳数据。函数运行后,通过访问大小
而且numDimensions
字段。
使用emxInitArray
API函数创建一个作为输出返回的数组,您事先不知道该数组的大小。例如,创建一个emxArray
对于两个尺寸未知的维度,你可以这样写:
emxArray_uint32_T *年代;emxInitArray_uint32_T(谨此告知,2);
emxArray
的emxCreateWrapper
而且emxCreateWrapperND
API函数使您能够将现有的内存和数据装入或包装到emxArray
将数据传递给生成的函数。这个C代码示例演示了如何使用emxCreateWrapper
.假设您已经为函数生成了源代码myFunction
它使用数据类型emxArray_uint32_T
.
#include#include #include "myFunction_emxAPI.h" #include "myFunction.h" int main(int argc, char *argv[]){/*创建一个包含uint32_T值的10 × 10 C数组*/ uint32_T x[100];Int k = 0;emxArray_uint32_T *pEmx = NULL;For (k = 0;k < 100;k++) {x[k] = (uint32_T) k;} /*将现有数据加载到emxArray */ pEmx = emxCreateWrapper_uint32_T(x,10,10);/*此处使用pEmx;*/ /*插入调用myFunction */ /*释放pEmx中分配的所有内存*/ /*这不会释放pEmx->数据,因为使用了包装器函数*/ emxDestroyArray_uint32_T(pEmx);/*未使用的*/ (void)argc; (void)argv; return 0; }
emxArray
数据此示例演示如何使用生成的包含emxArray
嵌套在其他内部的数据emxArray
数据。若要使用生成的代码,请在主函数或调用函数中初始化emxArray
数据从最下面的节点向上。
MATLAB算法
这个MATLAB算法遍历一个名为myarray
.每个结构都包含较低层的值数组。该算法对每个低级别数组的元素进行排序和求和结构体
.
% y是形式的结构数组%结构(“值”,[…]),“排序”,[…]], 'sum',…)函数y = processNestedArrays (y)% # codegencoder.cstructname (y,“myarray”);为I = 1:numel(y) y(I)。排序=排序(y(我). values);y (i)。金额= (y(我). values)之和;结束
生成MEX函数用于测试
作为第一步,为了能够测试算法,生成MEX函数。使用coder.typeof
的无界、可变大小的行向量手动指定输入结构体
,它们本身包含无界的、大小可变的行向量。
myarray = coder.typeof (...结构(“值”编码器。类型of(0, [1 inf]),...“排序”编码器。类型of(0, [1 inf]),...“和”, code .typeof(0)), [1 inf]);codegenarg游戏{myarray}processNestedArrays
检查生成的函数接口
MEX函数源代码包含专门的代码,使其能够与MATLAB运行时环境交互,这使其阅读起来更加复杂。要生成更简化的源代码,请生成库代码。
codegen配置:自由arg游戏{myarray}processNestedArrays报告
代码生成成功:要查看报告,请打开('codegen/lib/processNestedArrays/html/report.mldatx')。
检查生成的函数代码processNestedArrays.c
来自代码生成报告。生成的示例主文件c
方法创建和初始化输入,从而调用生成的函数代码emxCreate
API函数。
编写并使用您自己的自定义主文件进行初始化emxArray
数据
尽管生成的示例主要展示了如何调用生成的函数代码,但它不包含有关所需输入值的信息。使用示例main作为指导,编写您自己的主文件。使用您所选择的编码风格和首选项。指定输入的值,并根据需要插入预处理和后处理代码。
该文件processNestedArrays_main.c
显示了一个示例。该主文件使用emxArray
API函数来创建和初始化结构数据。对于生成的示例主文件和这个手工编写的主文件,代码都初始化emxArray
在底部(叶)节点上的数据,并将该数据分配给上面的节点。
类型processNestedArrays_main.c
#include#include #include "processNestedArrays_emxAPI.h" #include " processnestedarrays_h " static void print_vector(emxArray_real_T *v) {int i;printf(“(”);For (i = 0;我< v - >大小[1];i++) {if (I > 0) printf(" ");printf(" %。0 f”,v - >数据[我]);} printf(“\ n”);} int main(int argc, char *argv[]) {int i;静态双值_1[]= {5,3,4,1,2,6}; static double values_2[] = { 50, 30, 40, 10, 20, 60 }; static double values_3[] = { 42, 4711, 1234 }; static double * values[] = { values_1, values_2, values_3 }; static int values_len[] = { 6, 6, 3 }; /* Setup myarray emxArrays */ emxArray_myarray *myarr = emxCreate_myarray(1, 3); /* Create outer array */ for (i = 0; i < 3; i++) { /* Setup field 'values'. Don't allocate memory; reuse the data pointer. */ myarr->data[i].values = emxCreateWrapper_real_T(values[i], 1, values_len[i]); /* Initialize the 'sorted' field to the empty vector. */ myarr->data[i].sorted = emxCreate_real_T(1, 0); /* Initiailize the 'sum' field. */ myarr->data[i].sum = 0; } /* Call process function */ processNestedArrays(myarr); /* Print result */ for (i = 0; i < myarr->size[1]; i++) { printf(" values: "); print_vector(myarr->data[i].values); printf(" sorted: "); print_vector(myarr->data[i].sorted); printf(" sum: %.0f \n\n", myarr->data[i].sum); } /* Cleanup memory */ emxDestroyArray_myarray(myarr); /* Unused */ (void)argc; (void)argv; return 0; }
生成可执行文件并与MEX函数比较结果
使用提供的主文件,您可以为算法生成一个独立的可执行文件。
codegen配置:exearg游戏{myarray}processNestedArrays...processNestedArrays_main.c报告
代码生成成功:要查看报告,请打开('codegen/exe/processNestedArrays/html/report.mldatx')。
中定义的与独立可执行文件的输入相匹配的MEX函数的输入数据processNestedArrays_main.c
.
myarray =[结构(“值”, [5 3 4 1 2 6],“排序”0 (1,0),“和”0),...结构(“值”, [50 30 40 10 20 60],“排序”0 (1,0),“和”0),...结构(“值”, [42 4711 1234],“排序”0 (1,0),“和”, 0)];
将MEX函数结果与独立的可执行结果进行比较。
流(”。Mex output \n----------- \n');r = processNestedArrays_mex (myarray);disp (r (1));disp (r (2));disp (r (3));流('.exe output \n----------- \n');系统(“processNestedArrays”);
.mex output ----------- values: [5 34 12 6] sorted: [1 234 5 6] sum: 21 values: [50 30 40 10 20 60] sorted: [10 20 30 40 50 60] sum: 210 values: [42 4711 1234] sorted: [42 1234 4711] sum: 5987 .exe output ----------- /bin/bash: processNestedArrays: command not found
输出结果相同。
emxArray_char_T
字符串输入的数据在本例中,MATLAB函数在运行时改变字符向量的大小。由于向量的最终长度可以变化,因此生成的C代码将该向量实例化为动态大小的emxArray
.这个例子展示了如何编写一个main函数emxArray_char_T
用生成的函数接口。使用此示例作为使用emxArray_char_T
数据类型。
MATLAB算法
这个函数replaceCats
以一个字符向量作为输入,并用“velociraptor”和“velociraptor”替换单词“cat”或“cat”的所有实例。由于代码生成器不能在编译时确定输出长度,因此生成的代码使用emxArray
数据类型。
函数cstrNew = replaceCats(装运箱)% # codegencstrNew =取代(装运箱,“猫”,“迅猛龙”);cstrNew =取代(cstrNew,“猫”,“迅猛龙”);
生成的源代码
为的生成代码replaceCats
,将函数的输入类型指定为可变大小的字符数组。
t = coder.typeof (“一个”[1正]);codegenreplaceCatsarg游戏{t}报告配置:自由
代码生成成功:要查看报告,请打开('codegen/lib/replaceCats/html/report.mldatx')。
在生成的代码中,示例主文件/ codegen / lib / replaceCats /例子/ c
为编写自己的主函数提供模板。
从模板中创建一个Main函数
修改main函数以从命令行接受字符输入。使用emxCreate
而且emxCreateWrapper
API函数来初始化emxArray数据。在完成编写主源文件和头文件之后,将修改后的文件放在根文件夹中。
类型main_replaceCats.c
#include "main_replaceCats.h" #include "replaceCats_terminate.h" #include "replaceCats_emxAPI.h" #include "replaceCats_initialize.h" #include#include #define MAX_STRING_SZ 512 static void main_replaceCats(char *inStr){/*创建emxArray的和其他变量*/ emxArray_char_T *cstr = NULL;emxArray_char_T *cstrFinal = NULL;char outStr [MAX_STRING_SZ];int initCols = (int) strlen(inStr);int finCols;/*初始化输入和输出emxArrays */ cstr = emxCreateWrapper_char_T(inStr, 1, initCols);cstrFinal = emxCreate_char_T(1,0);/*调用emxArrays上生成的代码*/ replaceCats(cstr, cstrFinal);*/ finCols = cstrFinal->size[0]*cstrFinal->size[1];if (finCols >= MAX_STRING_SZ) {printf("错误:输出字符串超过最大大小。"); exit(-1); } memcpy(outStr, cstrFinal->data, finCols); outStr[finCols]=0; /* Print output */ printf("\nOld C string: %s \n", inStr); printf( "New C string: %s \n", outStr); /* Free the emxArray memory */ emxDestroyArray_char_T(cstrFinal); } int main(int argc, char *argv[]) { if (argc != 2 ) { printf("Error: Must provide exactly one input string, e.g.\n"); printf(">replaceCats \"hello cat\"\n"); exit(-1); } replaceCats_initialize(); main_replaceCats(argv[1]); replaceCats_terminate(); return 0; }
生成可执行文件
生成可执行代码:
t = coder.typeof (“一个”[1正]);codegenreplaceCatsarg游戏{t}配置:exemain_replaceCats.c
在平台上测试可执行文件,并根据需要修改主文件。例如,在Windows上,你会得到这样的输出:
C:\>replaceCats.exe "宠物主人称自己为'猫爸'"
老C弦:宠物主人称自己为“猫爸”
新C字串:宠物主人称自己为“迅猛龙爸爸”