主要内容

在生成的函数接口中使用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.h从代码生成报告。myFunction < >入口点函数的名称。

生成的代码还可以定义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必须手动释放由指向的内存数据

交互的实用函数emxArray数据

创造并与之互动emxArray在你的C/ c++代码中的数据,代码生成器导出一组C/ c++辅助函数和用户友好的API。使用这些函数可以确保正确地初始化和销毁emxArray数据类型。要使用这些函数,请为生成的头文件插入一个include语句myFunction < >_emxAPI.h在你的C代码中。myFunction < >入口点函数的名称。代码生成器生成的其他函数emxArray数据,定义在myFunction < >_emxutil.h,不适合手动使用。

默认生成的示例主文件自由dll,exe的调用emxArrayAPI函数。实例主代码初始化emxArray数据转换为泛型零值。要使用实际的数据输入和值,请修改示例main或创建自己的主文件。有关使用main函数的详细信息,请参见使用示例Main函数合并生成的代码

该表显示已导出的文件列表emxArrayAPI函数。类的初始行数、列数或维数为一些API函数所接受emxArray数据。每个维度都可以根据需要增长以容纳新数据。emxArray使用指针实例化的数组保留输入值的副本。类的大小不会在运行时更改输入变量的值emxArray

emxArrayHelper函数 描述

emxArray_ *emxCreate_(int rows, int cols)

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

emxArray_ *emxCreateND_(int numDimensions, int *size)

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

emxArray_ *emxCreateWrapper_( *data, int rows, int cols)

创建指向二维对象的指针emxArray.使用您提供的数据和内存,并将其包装到emxArray数据结构。集canFreeData防止无意中释放用户内存。

emxArray_ *emxCreateWrapperND_( *data, int numDimensions, int *size)

创建一个指向n维的指针emxArray.使用您提供的数据和内存,并将其包装到emxArray数据结构。集canFreeData防止无意中释放用户内存。

(emxArray_ **pEmxArray, int numDimensions)

对象的双指针分配内存emxArray

(emxArray_ *emxArray)

对象分配的动态内存emxCreateemxInitArray功能。

代码生成器导出emxArrayAPI函数仅用于作为函数入口参数的数组或由调用的函数使用的数组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])

函数接口声明输入参数一个输出参数BA_size包含大小为一个.在呼叫myuniquetolB_size包含大小为B

使用B_size确定…元素的数量B你可以在调用myuniquetolB_size [0]包含第一个维度的大小。B_size [1]包含第二个维度的大小。因此,元素的个数BB_size [0] * B_size [1].尽管BOne 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通过使用emxCreateemxInitArray功能

emxCreate而且emxCreateNDAPI函数创建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字段。

使用emxInitArrayAPI函数,用于创建一个作为输出返回的数组,对于该数组,您事先不知道数组的大小。例如,创建一个emxArray对于两个维度,任何一个维度的大小都是未知的,你可以这样写:

emxArray_uint32_T *年代;emxInitArray_uint32_T(谨此告知,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 × 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属性来创建和初始化输入,从而调用生成的函数代码emxCreateAPI函数。

编写并使用您自己的自定义主文件进行初始化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字串:宠物主人称自己为“迅猛龙爸爸”

另请参阅

|

相关的话题