在生成的函数接口中使用C数组
在大多数情况下,当你为MATLAB生成代码时®函数接受或返回数组,生成的C/ c++函数接口包含数组。要使用生成的函数接口,请了解如何定义和构造生成的C/ c++数组。尤其要学会使用emxArray
为表示动态分配数组而生成的数据结构。
在生成C/ c++代码时,将创建一个示例主文件,该文件显示如何对生成的函数代码使用数组。您可以使用示例main作为自己应用程序的模板或起点。
在生成的C/ c++代码中实现数组
代码生成器生成C/ c++数组定义,这些定义取决于数组元素类型以及数组使用静态还是动态内存分配。数组的两种内存分配需要两种不同的实现:
对于一个大小受预定义阈值限制的数组,生成的C/ c++定义由一个指向内存的指针和一个存储数组元素总数(数组大小)的整数组成。这个数组的内存来自程序堆栈,是静态分配的。
对于在编译时大小未知且没有界限的数组,或者界限超过预定义阈值的数组,生成的C/ c++定义由称为
emxArray
.当一个emxArray
时,中间存储边界将根据当前数组大小设置。在程序执行期间,当超出中间存储界限时,生成的代码将从堆中占用额外的内存空间,并将其添加到emxArray
存储。这个数组的内存是动态分配的。
默认情况下,在阈值大小范围内的数组不会在生成的代码中使用动态分配。您也可以关闭动态内存分配,并修改动态内存分配阈值。看到控制可变大小数组的内存分配.
下表列出了生成代码中数组表示的一些典型情况。
算法描述和数组大小 |
MATLAB函数 |
生成的C函数接口 |
---|---|---|
将它们放到固定大小的1 × 500行向量上。 固定大小,在阈值范围内。 |
函数B = create_vec0% # codegenB = 0 (1500);J = 1;为I = 1:500如果round(rand) B(1,j) = 1;J = J + 1;结束结束 |
void create_vec0(double B[500]) |
将它们推到一个以300个元素为界的可变大小行向量上。 可变大小,在阈值范围内。 |
函数B = create_vec% # codegenB = 0 (1,0);coder.varsize (“B”,[1 300],[0 1]);为I = 1:500如果round(rand) B = [1 B];结束结束 |
void create_vec(double B_data[], int B_size[2]) |
将它们推到一个以30,000个元素为界的可变大小行向量上。 大小可变,不受阈值限制。 |
函数B = create_vec2% # codegenB = 0 (1,0);coder.varsize (“B”,[1 30000],[0 1]);为I = 1:500如果round(rand) B = [1 B];结束结束 |
create_vec2(emxArray_real_T *B) |
创建一个数组,其大小由无界整数输入决定。 在编译时未知且无界。 |
函数Y = create_vec3(n)% # codegenY = int8(ones(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 {double *数据;int *大小;int allocatedSize;int numDimensions;boolean_T canFreeData;};
不寻求预测条目<类型>
而且<名称>
在代码生成之前。相反,在代码生成完成之后,检查文件
从代码生成报告。myFunction < >
_types.hmyFunction < >
入口点函数的名称。
生成的代码还可以定义emxArray
使用结构类型定义
语句,如在这些例子中。
typedef struct {emxArray_real_T *f1;} cell_wrap_0;Typedef struct {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 |
size向量的长度。在不跨越未分配或未使用内存的情况下可以访问的维数。 |
boolean_T canFreeData |
指示如何释放内存的布尔标志。仅供内部使用
|
交互的实用函数emxArray
数据
创造并与之互动emxArray
在你的C/ c++代码中的数据,代码生成器导出一组C/ c++辅助函数和用户友好的API。使用这些函数可以确保正确地初始化和销毁emxArray
数据类型。要使用这些函数,请为生成的头文件插入一个include语句
在你的C代码中。myFunction < >
_emxAPI.hmyFunction < >
入口点函数的名称。代码生成器生成的其他函数emxArray
数据,定义在
,不适合手动使用。myFunction < >
_emxutil.h
默认生成的示例主文件自由
,dll
,exe
的调用emxArray
API函数。实例主代码初始化emxArray
数据转换为泛型零值。要使用实际的数据输入和值,请修改示例main或创建自己的主文件。有关使用main函数的详细信息,请参见使用示例Main函数合并生成的代码.
该表显示已导出的文件列表emxArray
API函数。类的初始行数、列数或维数为一些API函数所接受emxArray
数据。每个维度都可以根据需要增长以容纳新数据。emxArray
使用指针实例化的数组保留输入值的副本。类的大小不会在运行时更改输入变量的值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)% # codegenA =排序(A);coder.varsize (“B”, [1 100], [0 1]);B = 0 (1,0);K = 1;为i = 2:长度(A)如果abs(A(k) - A(i)) > tol B = [B A(i)];K = i;结束结束
为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() {double A[100], B[100];int A_size[2] = {1,100};int B_size [2];int我;For (i = 0;I < 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;对于(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[]){/*创建一个10 × 10的uint32_T值的C数组*/ uint32_T x[100];Int k = 0;emxArray_uint32_T *pEmx = NULL;对于(k = 0;K < 100;{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是该形式的结构数组% struct('values',[…], 'sorted',[…]],“sum”,…)函数y = processNestedArrays(y)% # codegencoder.cstructname (y,“myarray”);为I = 1:数值(y) y(I)。排序=排序(y(i).values);y (i)。Sum = Sum (y(i).values);结束
生成用于测试的MEX函数
作为第一步,能够测试算法,生成一个MEX函数。使用coder.typeof
函数手动将输入指定为的无界、可变大小的行向量结构体
,它们本身包含无界的、可变大小的行向量。
Myarray = code .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显示了如何调用生成的函数代码,但它不包含所需输入值的信息。使用示例main作为指导,编写自己的主文件。使用您选择的编码风格和首选项。指定输入的值,并根据需要插入预处理和后处理代码。
该文件processNestedArrays_main.c
给出了一个例子。这个主文件使用emxArray
用于创建和初始化结构数据的API函数。对于生成的示例主文件和这个手写的主文件,代码初始化emxArray
底部(叶)节点上的数据,并将该数据分配给上面的节点。
类型processNestedArrays_main.c
#include#include #include "processNestedArrays_emxAPI.h" static void print_vector(emxArray_real_T *v) {int i;printf(“(”);For (i = 0;I < v->size[1];i++) {if (I > 0) printf(" ");printf(" %。0 f”,v - >数据[我]);} printf("] \n");} int main(int argc, char *argv[]) {int i;Static double values_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 = [struct(“值”, [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输出\n----------- \n');r = processNestedArrays_mex(myarray);disp (r (1));disp (r (2));disp (r (3));流('.exe输出\n----------- \n');如果isunix系统(”。/ processNestedArrays ')elseifispc系统(“processNestedArrays.exe”)其他的disp (“不支持平台”金宝app)结束
.mex输出 ----------- 值(3 4 5 1 2 6):排序:(1 2 3 4 5 6)金额:21个价值观:[50 30 40 10 20 60]排序:[10 20 30 40 50 60]总和:210值:[42 4711 1234]排序:[42 1234 4711]总和:5987 . exe输出 ----------- 值(3 4 5 1 2 6):排序:(1 2 3 4 5 6)金额:21个价值观:[50 30 40 10 20 60]排序:[10 20 30 40 50 60]总和:210值:[42 4711 1234]排序:[42 1234 4711]总和:5987 ans = 0
输出结果完全相同。
使用emxArray_char_T
字符串输入的数据
在本例中,MATLAB函数在运行时更改字符向量的大小。因为向量的最终长度可以变化,所以生成的C代码将向量实例化为动态大小emxArray
.这个例子展示了如何编写使用emxArray_char_T
与生成的函数接口。对象的使用,请使用此示例作为指南emxArray_char_T
数据类型。
MATLAB算法
这个函数replaceCats
以字符向量作为输入,并将单词“猫”或“猫”的所有实例替换为“迅猛龙”和“迅猛龙”。由于代码生成器不能在编译时确定输出长度,因此生成的代码使用emxArray
数据类型。
函数cstrNew = replaceCats(cstr)% # codegencstrNew = replace(cstr,“猫”,“迅猛龙”);cstrNew = replace(cstrNew,“猫”,“迅猛龙”);
生成源代码
为以下内容生成代码replaceCats
,将函数的输入类型指定为可变大小的字符数组。
T = code .typeof(“一个”[1正]);codegenreplaceCatsarg游戏{t}报告配置:自由
要查看报告,打开('codegen/lib/replaceCats/html/report.mldatx')
在生成的代码中,示例主文件/ codegen / lib / replaceCats /例子/ c
提供用于编写自己的main函数的模板。
从模板创建一个Main函数
修改main函数以从命令行获取字符输入。使用emxCreate
而且emxCreateWrapper
初始化emxArray数据的API函数。写完主源文件和头文件后,将修改后的文件放在根文件夹中。
类型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静态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 = code .typeof(“一个”[1正]);codegenreplaceCatsarg游戏{t}配置:exemain_replaceCats.c
代码生成成功。
在您的平台上测试可执行文件,并根据需要修改主文件。例如,在Windows上,你得到输出:
C:\>replaceCats.exe "宠物主人称自己为'Catdad'"
老C字串:宠物主人称自己为“猫爸”
新C字串:宠物主人称自己为“迅猛龙爸爸”