不同数据类型的传递

本小节介绍不同类型的数据,包括矩阵数据、字符串数据和结构数组等的传递方法。

1.矩阵

矩阵是MATLAB最基本的数据类型之一,但MATLAB中矩阵与C语言中二维数组有较大差别。首先,MATLAB中矩阵是按列方式存储的,而C语言的二维数组则是按行方式存储;其次,MATLAB中矩阵下标是从1开始,而C语言的二维数组下标是从0开始。因此,MATLAB矩阵常转换为C语言一维数组,而较少采用二维数组。MATLAB矩阵与C语言一维数组间转换公式如下。

code.matlab
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矩阵数据转换。程序清单如下。

code.c
/////////////////////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命令行中调用。

code.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”文件,输出结果为:

code.matlab
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。程序清单如下。

code.c
/////////////////////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命令行中调用。

code.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”文件,输出结果为:

code.matlab
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)创建结构体数据对象指针:

code.matlab
mxArray *Data=mxCreateStructMATrix(int m, int n, int nFields, const char **FieldsName);

参数:m mxArray类型矩阵的行数;

n mxArray类型矩阵的列数;

nFileds 每一结构体的字段数;

FieldsName 每一结构体的字段名;

(3)使用mx函数完成结构体数据赋值:

code.matlab
mxSetField(mxArray *Data, int Num, const char **FieldsName, (type) Value);

参数:Data 所创建的mxArray类型结构体;

Num 整个结构体的序号;

FieldsName 结构体中的字段名;

Value 与结构体中对应字段中数据类型相一致的数据。

下面以“h4.c”来说明MEX文件中如何创建结构体及其数据返回MATLAB的实现过程。

code.c
/////////////////////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命令行中调用。

code.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。