本小节介绍不同类型的数据,包括矩阵数据、字符串数据和结构数组等的传递方法。
1.矩阵
矩阵是MATLAB最基本的数据类型之一,但MATLAB中矩阵与C语言中二维数组有较大差别。首先,MATLAB中矩阵是按列方式存储的,而C语言的二维数组则是按行方式存储;其次,MATLAB中矩阵下标是从1开始,而C语言的二维数组下标是从0开始。因此,MATLAB矩阵常转换为C语言一维数组,而较少采用二维数组。MATLAB矩阵与C语言一维数组间转换公式如下。
C_array[j*M+i]=M_matrix(i,j)
式中,M为MATLAB矩阵M_matrix的行数。
将“h1.c”作一定改进后,得“h2.c”MEX文件,该文件以MATLAB最常用数据类型-矩阵为输入参数。在调用MEX文件时,MATLAB将矩阵型参数赋给prhs[],用户通过rP=mxGetPr(prhs[i])函数获取指向矩阵prhs[i]的指针,并赋给C一维数组rP,然后再通过M=mxGetM(prhs[i])和N=mxGetN(prhs[i])获取prhs[i]矩阵的行数M与列数N,这样就实现MATLAB矩阵至C一维数组的转换;C程序执行完成后,用户先对plhs[i]赋地址,再将plhs[i]地址赋给C一维数组lP,这样,用户只要对C一维数组lP操作,相应操作结果就存入了plhs[i]中,实现C一维数据至MATLAB矩阵数据转换。程序清单如下。
/////////////////////MEX头文件////////////////////////////////////////////
#include "mex.h"
#include "math.h"
////////////////////用户C程序 /////////////////////////////////////////////
void OutPut(FILE* fp1,int M,int N,double *rP,int ii)
{int i,j;
fprintf(fp1,"\n The %d Input Data is:\n",ii);
for(i=0;i<M;i++)
{
for(j=0;j<N;j++)fprintf(fp1," %7.2lf",rP[j*M+i]);
fprintf(fp1,"\n");
}
}
////////////////// 接口程序mexFunction/////////////////////////////////////
void mexFunction(int nlhs,mxArray *plhs[],int nrhs, mxArray *prhs[])
{ int i,M,N,ii,jj;
double *rP,*lP;
FILE *fp1;
if((fp1=fopen("OutPut2.txt","w"))==NULL){ mexErrMsgTxt(" Can't open OutPutfile\n");}
nlhs=nrhs;
for(i=0;i<nrhs;i++){
rP=mxGetPr(prhs[i]);//////获取指向矩阵prhs[i]的指针
M=mxGetM(prhs[i]);
N=mxGetN(prhs[i]);///获取prhs[i]矩阵的行数M与列数N
OutPut(fp1,M,N,rP,i);///////////////// 调用C程序
plhs[i]=mxCreateDoubleMATrix(M,N,mxREAL); //地址赋初值
lP=mxGetPr(plhs[i]); //////获取指向矩阵plhs[i]的指针
for(ii=0;ii<M;ii++)for(jj=0;jj<N;jj++)lP[jj*M+ii]=sqrt(rP[jj*M+ii]);//通过lP向plhs[i]赋值
}
fclose(fp1);
}
///////////////////结束////////////////////////////////////////////////////
在MATLAB命令窗口中将“h2.c”文件编译后,得动态链接子程序h2.dll,并在MATLAB命令行中调用。
>> mex h2.c
>> a=1:8
>> b=[a;3*a;5*a]
>> [L1,L2,L3]=h2(b,2*b,3*b)
L1 =
1.0000 1.4142 1.7321 2.0000 2.2361 2.4495 2.6458 2.8284
1.7321 2.4495 3.0000 3.4641 3.8730 4.2426 4.5826 4.8990
2.2361 3.1623 3.8730 4.4721 5.0000 5.4772 5.9161 6.3246
L2 =
1.4142 2.0000 2.4495 2.8284 3.1623 3.4641 3.7417 4.0000
2.4495 3.4641 4.2426 4.8990 5.4772 6.0000 6.4807 6.9282
3.1623 4.4721 5.4772 6.3246 7.0711 7.7460 8.3666 8.9443
L3 =
1.7321 2.4495 3.0000 3.4641 3.8730 4.2426 4.5826 4.8990
3.0000 4.2426 5.1962 6.0000 6.7082 7.3485 7.9373 8.4853
3.8730 5.4772 6.7082 7.7460 8.6603 9.4868 10.2470 10.9545
同时,由于用户C程序中执行了文件输出,在当前目录下生成“OutPut2.txt”文件,输出结果为:
The 0 Input Data is:
1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00
3.00 6.00 9.00 12.00 15.00 18.00 21.00 24.00
5.00 10.00 15.00 20.00 25.00 30.00 35.00 40.00
The 1 Input Data is:
2.00 4.00 6.00 8.00 10.00 12.00 14.00 16.00
6.00 12.00 18.00 24.00 30.00 36.00 42.00 48.00
10.00 20.00 30.00 40.00 50.00 60.00 70.00 80.00
The 2 Input Data is:
3.00 6.00 9.00 12.00 15.00 18.00 21.00 24.00
9.00 18.00 27.00 36.00 45.00 54.00 63.00 72.00
15.00 30.00 45.00 60.00 75.00 90.00 105.00 120.00
2.字符串
MATLAB和C程序间同样可以传递字符串类型的变量。对“h2.c”文件作一定改动后,得“h3.c”MEX文件。该文件中,MATLAB传入字符串变量至prhs[]中,mexFunction将字符串变量传入C字符串rP_buf中,后调用C程序进行字符串逆操作和操作结果输出,同时将操作结果返回mexFunction输出参数plhs[],以返回MATLAB。程序清单如下。
/////////////////////MEX头文件////////////////////////////////////////////
#include "mex.h"
#include "String.h"
////////////////////用户C程序 /////////////////////////////////////////////
void reword(FILE* fp1,char *rP_buf,char *lP_buf,int buf,int ii)
{int i;
fprintf(fp1,"\n The %d Input String is: %s\n",ii,rP_buf);
for(i=0;i<buf-1;i++){*(lP_buf+i)=*(rP_buf+buf-i-2);}
fprintf(fp1,"\n The %d Output String is: %s\n",ii,lP_buf);
}
////////////////// 接口程序mexFunction/////////////////////////////////////
void mexFunction(int nlhs,mxArray *plhs[],int nrhs, mxArray *prhs[])
{int i,j,buf;
char *rP_buf,*lP_buf;
FILE *fp1;
if((fp1=fopen("OutPut3.txt","w"))==NULL){ mexErrMsgTxt(" Can't open OutPutfile\n");}
nlhs=nrhs;
for(i=0;i<nrhs;i++){
if(mxIsChar(prhs[i])!=1)mexErrMsgTxt("Input must be a string");//参数检查
buf=(mxGetM(prhs[i])*mxGetN(prhs[i]))+1; //////获取每一个输入参数对应的字符串大小,
///由于CString 以NULL作为字符串结束标志,故加1
rP_buf=mxCalloc(buf,sizeof(char)); //////MATLAB内存管理机制
lP_buf=mxCalloc(buf,sizeof(char)); //////MATLAB内存管理机制
if(mxGetString(prhs[i],rP_buf,buf)==1) //由prhs[i]中获取输入参数
mexWarnMsgTxt("Not enough space.String is truncated");
reword(fp1,rP_buf,lP_buf,buf,i); ////调用C程序
plhs[i]=mxCreateString(lP_buf); //plhs[i]地址赋初值
mxFree(rP_buf); ///MATLAB内存管理机制
mxFree(lP_buf);
}
fclose(fp1);
}
////////////////结束////////////////////////////////////////////////////
在MATLAB命令窗口中将“h3.c”文件编译后,得动态链接子程序h3.dll,并在MATLAB命令行中调用。
>> mex h3.c
a='my book is yellow';
b='school is over';
c='the sky is blue';
[L1,L2,L3]=h3(a,b,c)
L1 =
wolley si koob ym
L2 =
revo si loohcs
L3 =
eulb si yks eht
同时,由于用户C程序中执行了文件输出,在当前目录下生成“OutPut3.txt”文件,输出结果为:
The 0 Input String is: my book is yellow
The 0 Output String is: wolley si koob ym
The 1 Input String is: school is over
The 1 Output String is: revo si loohcs
The 2 Input String is: the sky is blue
The 2 Output String is: eulb si yks eht
3.结构体与数组
与C语言一样,MEX文件结构体的数据是由若干记录组成,每一个记录保存在结构体的字段中,结构保存的数据可以是任意类型的MATLAB数据。在MEX文件中,创建结构体的基本过程为:
(1)准备不同字段的数据:可以由MATLAB创建,也可由C语言创建。
(2)创建结构体数据对象指针:
mxArray *Data=mxCreateStructMATrix(int m, int n, int nFields, const char **FieldsName);
参数:m mxArray类型矩阵的行数;
n mxArray类型矩阵的列数;
nFileds 每一结构体的字段数;
FieldsName 每一结构体的字段名;
(3)使用mx函数完成结构体数据赋值:
mxSetField(mxArray *Data, int Num, const char **FieldsName, (type) Value);
参数:Data 所创建的mxArray类型结构体;
Num 整个结构体的序号;
FieldsName 结构体中的字段名;
Value 与结构体中对应字段中数据类型相一致的数据。
下面以“h4.c”来说明MEX文件中如何创建结构体及其数据返回MATLAB的实现过程。
/////////////////////MEX头文件////////////////////////////////////////////
#include "mex.h"
////////////////////用户C程序:C语言定义结构体 ///////////////////////////////
struct Person
{char Name[10];
int Age;
char Sex[2];
char Address[30];
char Tel[15];
};
///////////用户C程序:C语言输入结构体数据 ///////////////////////////////////////
void InputPerson(int n,struct Person *P)
{ int i;char *InputFile;
FILE *fp1;
mexPrintf("Input The FileName Is Per.txt \n");
InputFile="Per.txt";
if((fp1=fopen(InputFile,"r"))==NULL){ mexErrMsgTxt(" Can't open InPutfile\n");}
for(i=0;i<n;i++)fscanf(fp1,"%s %d %s %s %s",
P[i].Name,&P[i].Age,P[i].Sex,P[i].Address,P[i].Tel);
fclose(fp1);
}
////////////////// 接口程序mexFunction/////////////////////////////////////
void mexFunction(int nlhs,mxArray *plhs[],int nrhs, mxArray *prhs[])
{int i,n;
struct Person *P;
mxArray *Data;
char **Fields;////mx结构体字段名
////////////////// 由 prhs[] 中取得MATLAB输入数据
n=(int)mxGetScalar(prhs[0]);
P=mxCalloc(n,sizeof(struct Person));///mx内存分配方式为结构体分配内存
Fields[0]="Name"; Fields[1]="Age";
Fields[2]="Sex"; Fields[3]="Address";
Fields[4]="Tel";
InputPerson(n,P); ////调用C程序
Data=mxCreateStructMATrix(1,1,5,Fields);///创建mx结构体
for(i=0;i<n;i++){ //////为mx结构体赋值
mxSetField(Data,0,Fields[0],mxCreateString(P[i].Name));
mxSetField(Data,0,Fields[1],mxCreateDoubleScalar((double)(P[i].Age)));
mxSetField(Data,0,Fields[2],mxCreateString(P[i].Sex));
mxSetField(Data,0,Fields[3],mxCreateString(P[i].Address));
mxSetField(Data,0,Fields[4],mxCreateString(P[i].Tel));
plhs[i]=mxCreateStructMATrix(1,1,5,Fields);///将输出参数创建为mx结构体并分配内存
plhs[i]=mxDuplicateArray(Data);////mxArray对象-结构体数值拷贝
}
mxDestroyArray(Data); ///释放mxArray对象内存
mxFree(P);////////mx内存释放方式将结构体内存释放
}
///////////////////结束////////////////////////////////////////////////////
“h4.c”程序中,首先由C语言定义了结构体Person,共包括5个字段:Name, Age, Sex, Address和Tel,各字段数据事先保存在当前目录的“Per.txt”文件中。
在MATLAB命令窗口中将“h4.c”文件编译后,得动态链接子程序h4.dll,并在MATLAB命令行中调用。
>> mex h3.c
>>[L1,L2,L3]=h4(3)
Input The FileName Is Per.txt
L1 =
Name: 'Liuh'
Age: 29
Sex: 'M'
Address: 'Street3'
Tel: '1390000'
L2 =
Name: 'Li'
Age: 29
Sex: 'M'
Address: 'Street4'
Tel: '1360000'
L3 =
Name: 'Su'
Age: 30
Sex: 'M'
Address: 'Street5'
Tel: '1350000'
从“h4.c”中可知,在MATLAB中调用h4.dll动态链接子程序后,操作流程为:
(1)操作流程寻找接口函数mexFunction后,从输入参数prhs[0]中取得需读入结构体记录数为3,并为结构体分配相应的内存空间;
(2)为结构赋于字段名;
(3)调用用户C程序,并从中读取结构体各字段的数据;
(4)流程返回接口程序;
(5)在接口程序中创建mxArray类型结构体;
(6)为mxArray类型结构体各字段赋由C程序中取得的数据;
(7)以矩阵数据复制方式将结构体数据拷贝至接口程序输出参数plhs[i]中;
(8)释放内存,返回MATLAB。