主要内容

使用C数组生成的函数接口

在大多数情况下,当你为MATLAB生成代码®接受或返回一个数组,函数生成的C / c++函数接口包含一个数组。使用生成的函数接口,学习如何生成的C / c++数组定义和构造。特别是,学会使用emxArray生成的数据结构来表示动态分配的数组。

生成C / c++代码时,主文件创建一个例子,展示了如何使用数组生成的函数代码。您可以使用这个例子主要作为模板或起点为您自己的应用程序。

实现数组生成的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:50 0如果轮(rand) B (j) = 1;j = + 1;结束结束
空白create_vec0(双B [500])

推到适应的行向量有界300个元素。

适应,在阈值有界。

函数B = create_vec% # codegenB = 0 (1,0);coder.varsize (“B”[300],[0 1]);i = 1:50 0如果轮(rand) B = (1 B);结束结束
空白create_vec(双B_data [],……int B_size [2])

推到适应的行向量有界30000个元素。

适应,而不是在阈值有界。

函数B = create_vec2% # codegenB = 0 (1,0);coder.varsize (“B”[30000],[0 1]);i = 1:50 0如果轮(rand) B = (1 B);结束结束
空白create_vec2 (emxArray_real_T * B)

创建一个数组的大小取决于一个无界的整数输入。

在编译时未知和无界。

函数y = create_vec3 (n)% # codegeny = int8 ((1, n));
空白create_vec3 (int n,…emxArray_int8_T * y)

emxArray动态数据结构定义

在生成的C / c++代码,emxArray数据结构定义的数据类型取决于它存储的元素。一般的定义:

struct emxArray_ <名称>{<类型> *数据;int *大小;int allocatedSize;int numDimensions;boolean_T canFreeData;};

的定义,<类型>表示数据类型和<名称>显示一个名字用来识别emxArray结构。代码生成器选择<名称>基于类型为墨西哥人定义代码生成中列出MATLAB的类型映射到生成的代码类型

作为一个例子,考虑emxArray定义生成的功能create_vec2。的<名称>emxArray_real_T<类型>

struct emxArray_real_T{双*数据;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 *数据;int *大小;int allocatedSize;int numDimensions;boolean_T canFreeData;}emxArray_cell_wrap_0;

此表描述了emxArray结构字段。

描述
<类型> *数据 指针数组的元素类型<类型>
int *大小 指针指向一个尺寸向量。矢量大小商店的第i个元素后的第i个维度的数组的长度。
int allocatedSize 数量的元素为数组分配内存。如果数组大小变化,基于新生成的代码是重新分配内存大小。
int numDimensions 长度尺寸向量。尺寸您可以访问的数量没有进入未分配或未使用的内存。
boolean_T canFreeData

布尔标志指示如何释放内存。仅供内部使用emxArray处理例程。

  • 真正的——自己生成的代码重新分配内存。

  • ——程序,实例化emxArray必须手动释放内存指出数据

效用函数进行交互emxArray数据

创建并与之交互emxArray数据在您的C / c++代码,代码生成器出口一组C / c++辅助函数与一个用户友好的API。使用这些函数来确保你正确地初始化和销毁emxArray数据类型。使用这些函数,插入一个包括语句生成的头文件< myFunction >_emxAPI.h在你的C代码。< myFunction >是你的入口点函数的名称。代码生成器产生的其他功能操作emxArray中定义的数据,< myFunction >_emxutil.h不用于手册使用。

在默认情况下生成的示例主要文件自由,dll,exe包括调用代码emxArrayAPI函数。这个例子主要代码初始化emxArray数据通用零值。使用实际数据输入和值,修改这个示例主要或创建自己的主文件。有关使用主要功能的更多信息,请参阅将生成的代码使用一个例子的主要功能

此表显示了导出的列表emxArrayAPI函数。的一些API函数接受最初的行数,列,或维度emxArray数据。每个维度可以成长,以适应新的数据。emxArray数组初始化使用指针保持输入值的一个副本。在运行时改变输入变量的值不会改变的大小emxArray

emxArrayHelper函数 描述

emxArray_ <名称> * emxCreate_ <名称> (int, int峡路)

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

emxArray_ <名称> * emxCreateND_ <名称> (int numDimensions, int *大小)

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

emxArray_ <名称> * emxCreateWrapper_ <名称>(<类型> *数据,int, int峡路)

创建一个指针指向一个二维的emxArray。使用数据和内存你提供包装成emxArray数据结构。集canFreeData预防不良用户内存的释放。

emxArray_ <名称> * emxCreateWrapperND_ <名称>(<类型> *数据、int numDimensions int *大小)

创建一个指针指向一个n维emxArray。使用数据和内存你提供包装成emxArray数据结构。集canFreeData预防不良用户内存的释放。

空白emxInitArray_ <名称> (emxArray_ <名称> * * pEmxArray, int numDimensions)

分配内存的指针指向一个的两倍emxArray

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

释放动态分配的内存的emxCreateemxInitArray功能。

代码生成器的出口emxArrayAPI函数入口点函数参数的数组或使用的函数调用coder.ceval

例子

使用函数接口的静态分配的数组

考虑到MATLAB函数myuniquetol为适应可变数据生成代码

函数B = myuniquetol (tol)% # codegen一种=(一个);coder.varsize (“B”[100],[0 1]);B = 0 (1,0);k = 1;我= 2:长度(A)如果abs ((k),(我))> tol B = (B) (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在默认阈值大小是有界的,代码生成器使用静态内存分配的数组。

生成的函数接口:

空白myuniquetol (const双A_data [], const int A_size[2],双托尔,双B_data [], int B_size [2])

接口声明输入参数的函数一个和输出参数BA_size包含的大小一个。后调用myuniquetol,B_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主要功能显示了如何调用myuniquetol

void main () {B双[100],[100];int A_size [2] = {100};int B_size [2];int我;(我= 0;我< 100;我+ +){[我]=(双)1 /我;}myuniquetol (A_size, 0.1, B, B_size);}

创建一个emxArray通过使用emxCreateemxInitArray功能

emxCreateemxCreateNDAPI函数创建一个emxArray根据需要,从堆中分配新的内存。然后,您可以使用emxArray作为输入或输出生成的代码。这个C代码示例展示了如何使用emxCreate。假设您已经生成的源代码一个函数myFunction使用数据类型emxArray_uint32_T

# include < stdio。h > # include < stdlib。h > # include " myFunction_emxAPI。h myFunction # include。h“int主要(int命令行参数个数,char * argv[]){/ *创建一个10 * uint32_T emxArray * / emxArray_uint32_T * pEmx = emxCreate_uint32_T (10,10);/ *初始化emxArray内存,如果需要* / int k = 0;(k = 0;k < 100;+ + k) {pEmx - >数据[k] = (uint32_T) k;}/ *使用pEmx数组;* / / * myFunction插入调用* / / *释放任何pEmx分配的内存* / / *这并免费pEmx - >数据* / emxDestroyArray_uint32_T (pEmx); /* Unused */ (void)argc; (void)argv; return 0; }

在本例中,您知道的初始大小emxArray。如果你不知道数组的大小,当你使用数组来存储输出,您可以输入的值为0关口字段。例如,如果您不知道列的数量,你可以写:

emxArray_uint32_T * pEmx = emxCreate_uint32_T (10 0);

数据结构适应生长所需的数据。函数运行后,确定输出大小通过访问大小numDimensions字段。

使用emxInitArrayAPI函数来创建一个数组作为输出返回,你事先不知道数组大小。例如,要创建一个emxArray两个维度,未知大小的尺寸,你可以写:

emxArray_uint32_T *年代;emxInitArray_uint32_T(谨此告知,2);

现有的数据加载到一个emxArray

emxCreateWrapperemxCreateWrapperNDAPI函数允许您或包装现有的内存和数据加载到一个emxArray通过数据生成的函数。这个C代码示例展示了如何使用emxCreateWrapper。假设您已经生成的源代码一个函数myFunction使用数据类型emxArray_uint32_T

# include < stdio。h > # include < stdlib。h > # include " myFunction_emxAPI。h myFunction # include。h“int主要(int命令行参数个数,char * argv[]){/ *创建uint32_T值10 C数组* / uint32_T x [100];int k = 0;emxArray_uint32_T * pEmx =零;(k = 0;k < 100;k + +) {x [k] = (uint32_T) k;}/ *现有数据加载到一个emxArray * / pEmx = emxCreateWrapper_uint32_T (x 10 10); /* Use pEmx here; */ /* Insert call to myFunction */ /* Deallocate any memory allocated in pEmx */ /* This DOES NOT free pEmx->data because the wrapper function was used */ emxDestroyArray_uint32_T(pEmx); /* Unused */ (void)argc; (void)argv; return 0; }

创建和使用嵌套emxArray数据

这个例子展示了如何使用生成的代码,其中包含emxArray嵌套在其他数据emxArray数据。使用生成的代码,你的主要功能或调用函数,初始化emxArray数据从底部节点。

MATLAB算法

这个MATLAB算法遍历一个数组的结构myarray。每个结构都包含一个底层数组的值。算法排序和底层数组的元素之和结构体

% y是一个数组的结构形式%结构(“值”,[…]),“排序”,[…]),“求和”,…)函数y = processNestedArrays (y)% # codegencoder.cstructname (y,“myarray”);i = 1:元素个数(y) y (i)。排序=排序(y(我). values);y (i)。金额= (y(我). values)之和;结束

生成墨西哥人功能进行测试

作为第一步,能够测试算法,生成一个墨西哥人的功能。使用coder.typeof手动输入指定为一个无界的函数,适应行向量结构体,包含无限,适应行向量。

myarray = coder.typeof (结构(“值”编码器。类型of(0, [1 inf]),“排序”编码器。类型of(0, [1 inf]),“和”coder.typeof(0)),[1正]);codegenarg游戏{myarray}processNestedArrays
代码生成成功。

检查生成的函数接口

墨西哥人函数源代码包含专门的代码,使其与MATLAB运行时环境接口,这使得它更复杂的阅读。产生更多的简化的源代码,生成库代码。

codegen配置:自由arg游戏{myarray}processNestedArrays报告
代码生成成功:查看报告,打开(“codegen / lib / processNestedArrays / html / report.mldatx”)

检查生成的函数代码processNestedArrays.c从代码生成报告。主文件生成的例子c显示了如何调用生成的函数代码通过创建和初始化输入emxCreateAPI函数。

编写和使用您自己的定制的主文件来初始化emxArray数据

尽管主要生成的示例展示了如何调用生成的函数代码,它不包含信息所需的输入值。使用这个示例主要作为指导,编写自己的主文件。使用您选择的编码风格和偏好。指定输入的值并根据需要插入前和后期处理代码。

该文件processNestedArrays_main.c显示了一个示例。该主文件使用emxArrayAPI函数来创建和初始化数据结构。生成的示例主要文件和这个手写的主要文件,初始化的代码emxArray数据在底部(叶)节点,向上面的节点分配数据。

类型processNestedArrays_main.c
# include < stdio。h > # include < stdlib。h > # include " processNestedArrays_emxAPI。h processNestedArrays # include。h“静态孔隙print_vector (emxArray_real_T * v) {int我;printf (“(”);(我= 0;我< v - >大小[1];我+ +){如果(我> 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; }

生成一个可执行的和比较结果与墨西哥人的功能

使用提供的主文件,您可以生成一个独立的可执行的算法。

codegen配置:exearg游戏{myarray}processNestedArraysprocessNestedArrays_main.c报告
代码生成成功:查看报告,打开(“codegen / exe / processNestedArrays / html / report.mldatx”)

为墨西哥人函数声明输入数据相匹配的输入独立的可执行文件,定义processNestedArrays_main.c

myarray =[结构(“值”(3 4 5 1 2 6),“排序”0 (1,0),“和”0),结构(“值”(50 30 40 10 20 60),“排序”0 (1,0),“和”0),结构(“值”(42 4711 1234),“排序”0 (1,0),“和”,0)];

比较了墨西哥人函数结果与独立的可执行的结果。

流(”。墨西哥人输出\ 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(装运箱)% # codegencstrNew =取代(装运箱,“猫”,“迅猛龙”);cstrNew =取代(cstrNew,“猫”,“迅猛龙”);

生成的源代码

生成的代码replaceCats,指定函数的输入类型为适应可变字符数组。

t = coder.typeof (“一个”[1正]);codegenreplaceCatsarg游戏{t}报告配置:自由
代码生成成功:查看报告,打开(“codegen / lib / replaceCats / html / report.mldatx”)

在生成的代码中,主文件的例子/ codegen / lib / replaceCats /例子/ c为编写自己的主要功能提供了一个模板。

从模板创建一个主要功能

修改的主要功能从命令行字符输入。使用emxCreateemxCreateWrapperAPI函数来初始化您的emxArray数据。在你写完你的主要源文件和头文件,把修改的文件放在根文件夹。

类型main_replaceCats.c
# include“main_replaceCats。h replaceCats # include。h replaceCats_terminate # include。h replaceCats_emxAPI # include。h replaceCats_initialize # include。h”# include <字符串。h > # include < stdio。512 h > # define MAX_STRING_SZ静态空main_replaceCats (char * inStr){/ *创建emxArray &其他变量* / emxArray_char_T *装运箱=零;emxArray_char_T * cstrFinal =零;char outStr [MAX_STRING_SZ];int initCols = (int) strlen (inStr);int finCols;/ *初始化输入和输出emxArrays * /装运箱= emxCreateWrapper_char_T (inStr 1 initCols);cstrFinal = emxCreate_char_T (1,0); /* Call generated code on emxArrays */ replaceCats(cstr, cstrFinal); /* Write output string data with null termination */ finCols = cstrFinal->size[0]*cstrFinal->size[1]; if (finCols >= MAX_STRING_SZ) { printf("Error: Output string exceeds max size."); 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"The pet owner called themselves a 'Catdad'"

老C字符串:宠物主人叫自己“Catdad”

新的C字符串:宠物主人叫自己“Velociraptordad”

另请参阅

|

相关的话题