主要内容

在生成的函数接口中使用C阵列

在大多数情况下,当您为MATLAB生成代码时®接受或返回数组的函数,生成的C / C ++函数接口包含一个数组。要使用生成的函数接口,请了解如何定义和构造生成的C / C ++阵列。特别是,学会使用emxarray生成的数据结构以表示动态分配的数组。

生成C / C ++代码时,会创建示例主文件,以显示如何使用生成的功能代码使用阵列。您可以使用示例主要作为您自己应用程序的模板或起点。

在生成的C / C ++代码中实现数组

代码生成器生成C / C ++阵列定义,依赖于数组元素类型以及阵列是否使用静态或动态内存分配。数组的两种内存分配需要两个不同的实现:

  • 对于大小在预定阈值内界定的阵列,所生成的C / C ++定义由指向存储器的指针和存储数组元素的总数,数组大小的指针组成。此阵列的内存来自程序堆栈,在静态分配。

  • 对于一个数组,其尺寸是未知的,无界在编译时,或者其结合的超过预定阈值,将所生成的C / C ++定义包括的数据结构称为emxarray。当AN.emxarray是创建的,基于当前数组大小设置中间存储界限。在程序执行期间,由于超过中间存储界限,生成的代码从堆中占用额外的内存空间,并将其添加到emxarray存储。这个数组的内存是动态分配的。

默认情况下,在阈值大小内界定阵列不在所生成的代码中使用的动态分配。另外,您也可以禁用动态内存分配和更改动态内存分配阈值。看可变大小阵列的控制内存分配

此表列出了在生成的代码数组表示的几个典型例。

算法描述和数组大小

Matlab功能

生成的C功能界面

地方的人到一个固定大小的1 * 500行向量。

固定大小,限制在阈值内。

功能b = create_vec0.%#codegen.B =零(1,500);j = 1;对于I = 1:500如果B(1,j) = 1;J = J + 1;结束结束
void create_vec0(双b [500])

将介绍在300元素的可变大小行向量上。

可变大小,阈值范围内。

功能B = create_vec%#codegen.b =零(1,0);编码器.Varsize(“B”[300], [0 1]);对于I = 1:500如果圆形(兰特)b = [1 b];结束结束
void create_vec(double b_data [],int b_size [2])

将介绍在30,000元素的可变大小行向量上。

可变大小,不在阈值范围内。

功能b = create_vec2.%#codegen.b =零(1,0);编码器.Varsize(“B”[30000], [0 1]);对于I = 1:500如果圆形(兰特)b = [1 b];结束结束
空隙create_vec2(emxArray_real_T * B)

创建一个由无界整数输入确定的大小的数组。

在编译时未知和无限制。

功能Y = create_vec3(n)的%#codegen.Y = 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 {double *数据;int *大小;int allocatedSize;int numDimensions;boolean_T canFreeData;};

不要试图预测参赛作品前代码生成。取而代之的是,之后的代码生成完成后,检查文件_types.h从代码生成报告。是您的入学点函数的名称。

生成的代码也可以定义emxarray结构用的typedef语句,如下面的例子。

typedef struct {emxarray_real_t * f1;cell_wrap_0;typedef struct {cell_wrap_0 *数据;int *大小;int allocatedSize;int numDimensions;boolean_T canFreeData;} emxarray_cell_wrap_0;

该表描述了emxarray结构字段。

田野 描述
*数据 指向类型的元素数组
INT *尺寸 指向大小向量的指针。尺寸矢量的第i个元素存储阵列的第一维度的长度。
INT allocatedSize 为数组分配的内存元素数。如果数组大小更改,则生成的代码基于新大小重新划分内存。
INT numDimensions 尺寸矢量的长度。无需交叉到未分配或未使用的内存即可访问的维度数。
boolean_T canFreeData

Boolean标志,指示如何解析内存。仅由内部使用emxarray处理例程。

  • 真实- 生成的代码将自己删除内存。

  • - 实例化的程序emxarray必须手动解除分配指向的存储器数据

与互动的实用功能emxarray数据

去创造和与emxarray在C/ c++代码中,代码生成器导出一组带有用户友好API的C/ c++ helper函数。使用这些函数可以确保正确地初始化和销毁emxarray数据类型。要使用这些函数,请为生成的头文件插入一个include语句_emxAPI.h在你的C代码。是您的入学点函数的名称。由操作的代码生成器产生的其他功能emxarray数据,定义_emxutil.h,不适用于手动使用。

默认生成的示例主文件自由DLL.,和ex代码包括拨打电话emxarrayAPI函数。的例子中主代码初始化emxarray数据到通用的零值。要使用实际的数据输入和值,请修改示例main或创建您自己的main文件。有关使用main函数的更多信息,请参见使用示例主函数并入生成的代码

此表显示导出列表emxarrayAPI函数。一些API函数接受初始的行数,列或尺寸emxarray数据。每个维度都可以增长以适应所需的新数据。

emxarray助手功能 描述

emxArray_ *emxCreate_(int rows, int cols)

创建指向二维的指针emxarray,数据元素初始化为零。为数据分配新内存。

emxarray_ * emxcreatend_ (int numdimensions,int * size)

创建指向n维的指针emxarray,数据元素初始化为零。为数据分配新内存。

emxarray_ * emxcreatewrapper_ *数据,int行,int cols)

创建指向二维的指针emxarray。使用您提供的数据和内存并将其包装到emxarray数据结构。套canfreedata.防止无意中释放用户存储器。

emxarray_ * emxcreatewrappernd_ *数据,int num.imensions,int * size)

创建指向n维的指针emxarray。使用您提供的数据和内存并将其包装到emxarray数据结构。套canfreedata.防止无意中释放用户存储器。

void emxinitarray_ (emxarray_ ** pemxarray,int num.imensions)

为双指针分配内存emxarray

空白emxDestroyArray_ <名称> (emxArray_ <名称> * emxArray)

释放由此分配的动态内存emxCreate或者emxInitArray功能。

代码生成器导出emxarrayAPI仅函数对于作为入门点函数参数的数组或由函数使用的阵列函数编码器.CEVAL.

例子

使用函数界面进行静态分配的数组

考虑MATLAB功能myuniquetol生成可变大小数据的代码

功能b = yuliqueTol(a,tol)%#codegen.a = sort(a);编码器.Varsize(“B”[1 100],[0 1]);b =零(1,0);K = 1;对于i = 2:长度(a)如果ABS(a(k) -  a(i))> tol b = [b a(i)];k = i;结束结束

生成代码myuniquetol。使用Coder.typeof.将输入类型指定为有界的可变大小数组和标量双精度数组。

Codegen.-config:LIB-reportmyuniquetol-  args.{coder.typeof(0,[1 100],[0 1]),Coder.typeof(0)}

声明编码器.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.包含大小一种。打电话给myuniquetolB_SIZE包含大小B.

使用B_SIZE确定要素的数量B.您可以在调用后访问myuniquetolB_size [0]包含第一维的大小。B_size [1]包含第二维度的大小。因此,元件的数目B.b_size [0] * b_size [1]。即使是B.100.在C代码元素,只b_size [0] * b_size [1]元素包含有效数据。

此C主要功能显示如何调用myuniquetol

void main(){double a [100],b [100];int a_size [2] = {1,100};int b_size [2];INT I;for(i = 0; i <100; i ++){a [i] =(双)1 / i;MyUnquiqueol(a,a_size,0.1,b,b_size);}

创建一个emxarray通过使用emxCreate或者emxInitArray功能

emxCreateemxcreatem.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×10UINT32_T EMXARRAY * / EMXARRAY_UINT32_T * PEMX = EMXCREATE_UINT32_T(10,10);/ *如果需要,初始化EMXARRAY存储器* / int k = 0;for(k = 0; k <100; ++ k){pemx->数据[k] =(uint32_t)k;} / *在这里使用PEMX数组;* // *插入呼叫myfunction * // *在pemx * // *中删除分配的任何内存,这是免费的pemx-> data * / emxdestroyarray_uint32_t(pemx);/ *未使用* /(空白)argc;(空虚)argv;返回0;}

在这个例子中,您知道初始大小emxarray。如果您不知道阵列的大小,就像使用数组存储输出一样,您可以输入值0关口字段。例如,如果你不知道列数,你可以写:

emxArray_uint32_T *pEmx = emxCreate_uint32_T(10,0);

数据结构会根据需要增长以容纳数据。函数运行后,通过访问尺寸numDimensions字段。

使用emxInitArrayAPI函数来创建一个返回输出数组,对此你不事先知道数组的大小。例如,为了创建一个emxarray两个维度,在维度中有未知的尺寸,可以写:

emxArray_uint32_T * S;emxInitArray_uint32_T(S,2);

将现有数据加载到emxarray

EmxcreateWrapper.emxCreateWrapperNDAPI函数,可以加载或包装现有存储器和数据转换成emxarray将数据传递到一个生成的函数。这个C代码示例展示了如何使用EmxcreateWrapper.。假设您已经为函数生成了源代码myfunction.使用数据类型emxArray_uint32_T

#include  #include  #include“myfunction_emxapi.h”#include“myfunction.h”int main(int argc,char * argv []){/ *创建一个10×10c uint32_t值阵列* / 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);/ *未使用* /(空白)argc;(空虚)argv; return 0; }

创建和使用嵌套emxarray数据

这个例子展示了如何使用生成的代码emxarray数据嵌套在其他emxarray数据。要使用生成的代码,在主函数或调用函数中,初始化emxarray来自底部节点的数据。

MATLAB算法

此MATLAB算法通过调用的结构数组迭代myArray.。每个结构都包含较低级别的值阵列。该算法为每个算法排序和总和较低级别数组的元素塑造

% y是窗体结构的数组%结构(“值”,[…]),“排序”,[…]],“sum”,…)功能Y = ProcessnestedArrays(Y)%#codegen.coder.cstructname (y,'myArray');对于i = 1:numel(y)y(i).sorted = sort(y(i).values);Y(i).sum = sum(y(i).values);结束

生成MEX函数进行测试

作为第一步,为了能够测试算法,生成MEX功能。使用Coder.typeof.手动指定输入作为无界,可变大小的行向量的输入结构,本身包含无限的可变大小的行向量。

myarray = coder.typeof(...struct(“价值”,coder.typeof(0,[1 inf]),...'排序',coder.typeof(0,[1 inf]),...'总和',coder.typeof(0)),[1 inf]);Codegen.-  args.{} myArray的processnestedarrays.
代码生成成功。

检查生成的功能接口

MEX函数源代码包含专用代码,使其能够与MATLAB运行时环境进行接口,这使得读取更复杂。要生成更多简化的源代码,请生成库代码。

Codegen.-config:LIB-  args.{} myArray的processnestedarrays.-report
代码生成成功:要查看报告,请打开('codegen / lib / processnestedArrays / html / export.mldatx')。

检查生成的函数代码processNestedArrays.c从代码生成报告。所生成的示例主文件c示出了如何通过创建并初始化带有输入调用生成的功能码emxCreateAPI函数。

写和使用你自己的自定义主文件来初始化emxarray数据

尽管生成的示例main显示了如何调用生成的函数代码,但它不包含所需输入值的信息。以main为例,编写自己的main文件。使用您所选择的编码风格和首选项。指定输入的值,并根据需要插入预处理和后处理代码。

文件processnestedarrays_main.c.显示一个例子。此主文件使用emxarray用于创建和初始化结构数据的API函数。对于生成的示例主文件和这个手动编写的主文件,代码初始化emxarray底部(叶)节点的数据,并将该数据分配给上面的节点。

类型processnestedarrays_main.c.
#include  #include  #include“processnestedarrays_emxapi.h”#include“processnestedarrays.h”静态void print_vector(emxarray_real_t * v){int i;printf(“[”);for(i = 0; i 尺寸[1]; i ++){if(i> 0)printf(“”);printf(“%。0f”,v->数据[i]);printf(“] \ n”);int main(int argc,char * argv []){int i;静态双值_1 [] = {5,3,4,1,2,6};静态双值_2 [] = {50,30,40,10,20,60};静态双值_3 [] = {42,4711,1234};静态双*值[] = {value_1,值_2,值_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.-config:exe.-  args.{} myArray的processnestedarrays....processnestedarrays_main.c.-report
代码生成成功:要查看报告,请打开('codegen / exe / processnestedArrays / html / export.mldatx')。

中定义的独立可执行文件的输入匹配MEX函数的输入数据processnestedarrays_main.c.

myArray = [struct(“价值”,[5 3 4 1 2 6],'排序',零(1,0),'总和',0),...struct(“价值”[50 30 40 10 20 60],'排序',零(1,0),'总和',0),...struct(“价值”,[42 4711 1234],'排序',零(1,0),'总和',0)];

比较MEX函数结果与独立的可执行结果。

fprintf('.Mex output \n----------- \n');R = processNestedArrays_mex(myarray中);DISP(R(1));DISP(R(2));DISP(R(3));fprintf('.exe output \n----------- \n');系统(“processNestedArrays”);
.mex输出-----------值:[5 3 4 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输出----------- /斌/庆典:processNestedArrays:命令不发现

输出结果是相同的。

使用emxarray_char_t.带字符串输入的数据

在此示例中,MATLAB函数在运行时更改字符向量的大小。因为矢量的最终长度可以各不相同,所以生成的C代码将向量实例为动态尺寸emxarray。这个例子说明了如何写一个主要功能,它使用emxarray_char_t.使用生成的功能界面。使用此示例作为与之合作的指南emxarray_char_t.数据类型。

MATLAB算法

功能更换者将一个字符向量作为输入,用'velociraptor'和'velociraptor'替换单词'cat'或'cat'的所有实例。因为代码生成器无法在编译时确定输出长度,所以生成的代码使用emxarray数据类型。

功能cstrNew = replaceCats(装运箱)%#codegen.cstrnew =替换(cstr,'猫'“迅猛”);cstrnew =替换(cstrnew,'猫'“迅猛龙”);

生成的源代码

生成代码更换者中,指定输入类型的功能作为可变大小字符数组。

T = coder.typeof('A'[1 INF]);Codegen.更换者-  args.{T}-report-config:LIB
代码生成成功:要查看报告,打开('codegen/lib/replaceCats/html/report.mldatx')。

在生成的代码中,示例主文件/codegen/lib/replaceCats/examples/main.c提供用于编写自己的主函数的模板。

从模板创建一个主要功能

修改主函数以取出命令行的字符输入。使用emxCreateEmxcreateWrapper.用于初始化emxArray数据的API函数。写完主源文件和头文件后,将修改后的文件放在根文件夹中。

类型main_replacecats.c.
的#include “main_replaceCats.h” 的#include “replaceCats.h” 的#include “replaceCats_terminate.h” 的#include “replaceCats_emxAPI.h” 的#include “replaceCats_initialize.h” 的#include 的的#include 中#限定MAX_STRING_SZ 512个静态无效main_replaceCats(字符* INSTR){/ *创建emxArray的&其它变量* / emxArray_char_T * CSTR = NULL;emxArray_char_T * cstrFinal = NULL;炭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->大小写入输出串数据[0] * cstrFinal->尺寸[1];如果(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('A'[1 INF]);Codegen.更换者-  args.{T}-config:exe.main_replacecats.c.
代码生成成功。

在您的平台上测试可执行文件,并根据需要修改主文件。例如,在Windows上,你会得到如下输出:

C:\>replaceCats.exe“宠物主人称自己为‘猫爸’”

旧的c字符串:宠物老板称为自己'catdad'

新的c字符串:宠物老板称为“velociraptordad”

也可以看看

|

相关主题