使用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
数据在您的C / c++代码,代码生成器出口一组C / c++辅助函数与一个用户友好的API。使用这些函数来确保你正确地初始化和销毁emxArray
数据类型。使用这些函数,插入一个包括语句生成的头文件
在你的C代码。< myFunction >
_emxAPI.h< myFunction >
是你的入口点函数的名称。代码生成器产生的其他功能操作emxArray
中定义的数据,
不用于手册使用。< myFunction >
_emxutil.h
在默认情况下生成的示例主要文件自由
,dll
,exe
包括调用代码emxArray
API函数。这个例子主要代码初始化emxArray
数据通用零值。使用实际数据输入和值,修改这个示例主要或创建自己的主文件。有关使用主要功能的更多信息,请参阅将生成的代码使用一个例子的主要功能。
此表显示了导出的列表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 (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])
接口声明输入参数的函数一个
和输出参数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主要功能显示了如何调用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
通过使用emxCreate
或emxInitArray
功能
的emxCreate
和emxCreateND
API函数创建一个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
字段。
使用emxInitArray
API函数来创建一个数组作为输出返回,你事先不知道数组大小。例如,要创建一个emxArray
两个维度,未知大小的尺寸,你可以写:
emxArray_uint32_T *年代;emxInitArray_uint32_T(谨此告知,2);
现有的数据加载到一个emxArray
的emxCreateWrapper
和emxCreateWrapperND
API函数允许您或包装现有的内存和数据加载到一个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
显示了如何调用生成的函数代码通过创建和初始化输入emxCreate
API函数。
编写和使用您自己的定制的主文件来初始化emxArray
数据
尽管主要生成的示例展示了如何调用生成的函数代码,它不包含信息所需的输入值。使用这个示例主要作为指导,编写自己的主文件。使用您选择的编码风格和偏好。指定输入的值并根据需要插入前和后期处理代码。
该文件processNestedArrays_main.c
显示了一个示例。该主文件使用emxArray
API函数来创建和初始化数据结构。生成的示例主要文件和这个手写的主要文件,初始化的代码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}processNestedArrays…processNestedArrays_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
为编写自己的主要功能提供了一个模板。
从模板创建一个主要功能
修改的主要功能从命令行字符输入。使用emxCreate
和emxCreateWrapper
API函数来初始化您的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”