matlab 和c混合编程-------------------基础

mtalab第一次调用C编程之前,需运行mex操作,此操作在windows系统下是一个bat的批处理文件

>> mex -setup             //在matlab 的command window下运行此命令
Please choose your compiler for building external interface (MEX) files:
 
Would you like mex to locate installed compilers [y]/n? y  //是否调用本地安装好的c编译软件

 

Select a compiler: 
[1] Lcc-win32 C 2.4.1 in D:\PROGRA~1\MATLAB\R2010b\sys\lcc 
[2] Microsoft Visual C++ 2010 in C:\Program Files\Microsoft Visual Studio 10.0 
[3] Microsoft Visual C++ 2008 SP1 in C:\Program Files\Microsoft Visual Studio 9.0 
[4] Microsoft Visual C++ 6.0 in C:\Program Files\Microsoft Visual Studio 
 
[0] None 
 
Compiler: 1    //也可以选择2
 
Please verify your choices:
 
Compiler: Lcc-win32 C 2.4.1
Location: C:\PROGRA~1\MATLAB\R2010b\sys\lcc
 
Are these correct [y]/n? y     //确认正确
 
Trying to update options file: C:\Users\XJT\AppData\Roaming\MathWorks\MATLAB\R2010b\mexopts.bat
From template:              C:\PROGRA~1\MATLAB\R2010b\bin\win32\mexopts\lccopts.bat
 
Done . . .
 
**************************************************************************
  Warning: The MATLAB C and Fortran API has changed to support MATLAB
           variables with more than 2^32-1 elements.  In the near future
           you will be required to update your code to utilize the new
           API. You can find more information about this at:
           http://www.mathworks.com/support/solutions/en/data/1-5C27B9/?solution=1-5C27B9
           Building with the -largeArrayDims option enables the new API.
**************************************************************************
 
>>

到此,matlab调用C的混合编程环境已经搭建好,下面举个简单例子:


#include
void mexFunction(int nlhs ,mxArray *plhs[] ,int nrhs, const mxArray *prhs[])
{
    mexPrintf("Hello word!");
}

把上面程序保存为一个C文件,如 hello.c

在command window下运行

>> mex hello.c

结束之后在current folder 窗口里会有一个hello.mexw32文件。

在command window下运行

>> hello()
Hello word!

一个简单的hello word程序已经完成。


程序很简单,但和我们平常写的C程序并不一样,程序必须包含mex.h头文件。

C的入口函数为mexFunction相当于我们常写的main函数,此函数没有返回值,必须是void型。

nlhs 为函数输出的个数,plhs为函数输出值,

nrhs 为函数输入的个数,prhs为函数参数值。 

举例:

如.m函数为   function  [x,y]=shiftX(a,b,c) 

则在写成C语言,nlhs为2,plhs为x,y,nrhs为3,prhs为a,b,c 

C函数如何引用参数:

如果是数组则用mxGetPr(prhs[loc])   //loc是参数的位置,如是第一个参数则为0,如第二个则为1

如果是单个数值mxGetScalar(prhs[loc])

为了让大家能更直观地了解参数传递的过程,我们把hello.c改写一下,使它能根据输入参数的变化给出不同的屏幕输出:
//hello.c 2.0
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{

int i;
i=mxGetScalar(prhs[0]);
if(i==1)
  mexPrintf("hello,world!\n");
else
  mexPrintf("大家好!\n");

}
  将这个程序编译通过后,执行hello(1),屏幕上会打出:
hello,world!
  而hello(0)将会得到:
大家好!


在这个程序里,除了用到了屏幕输出函数mexPrintf(用法跟c里的printf函数几乎完全一样)外,还用到了一
个函数:mxGetScalar,调用方式如下:
i=mxGetScalar(prhs[0]);
  "Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。
  既然有标量,显然还应该有矢量,否则矩阵就没法传了。看下面的程序:

//hello.c 2.1
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[],
     int nrhs, const mxArray *prhs[])
{
int *i;
i=mxGetPr(prhs[0]);
if(i[0]==1)
  mexPrintf("hello,world!\n");
else
  mexPrintf("大家好!\n");
}
  这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就没法对它进行计算。  为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来:
//show.c 1.0


#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{

double *data;
int M,N;
int i,j;
data=mxGetPr(prhs[0]); //获得指向矩阵的指针
M=mxGetM(prhs[0]); //获得矩阵的行数
N=mxGetN(prhs[0]); //获得矩阵的列数
for(i=0;i
{
  for(j=0;j

   mexPrintf("%4.3f  ",data[j*M+i]);

  mexPrintf("\n");

}
}
  编译完成后,用下面的命令测试一下:
  a=1:10;
  b=[a;a+1];
  show(a)
  show(b)
  需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组data后对应于data[j*M+i].

如果是多维数组并不能用Arr[i][j]的格式寻址,在参数在C里只是一维数组,一维数组按列排列,C语言是按行排列的,
如[a b c d;e f g h]C语言在内存中是按a b c d e f g h排列,而matlab是按 a e b f c g d h排列的。
如果要变成C语言可Arr[i][j]索引的格式,可用for循环转化,下面举个三维的例子:
   
   
for(i=0;i         for(j=0;j         inYr[i][j] = inY[j*inM+i];
        inYg[i][j] = inY[inM*inN+j*inM+i];
        inYb[i][j] = inY[2*inM*inN+j*inM+i];
        }
转化前,只可以按inY[loc]索引,转换后可以按inYr[i][j]格式索引。


-------------------------------------------------------------------------------------------------------------------------------------------------------

输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。

我这样理解,你输入的数据 实际上在matlab 中已经占有内存存储了,但是你现在要在mex 函数中将传入的数据进行传递,也就是说要复制给另外一个变量,那么另外一个变量实际是你在mex函数中新创建的,在matlab 函数中并没有分配空间,于是你要在这个变量分配一定的空间。

由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下:
mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag)
m:待申请矩阵的行数
n:待申请矩阵的列数

为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输
//reverse.c 1.0

#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[],

                         int nrhs, const mxArray *prhs[])
{
double *inData;
double *outData;
int M,N;
int i,j;
inData=mxGetPr(prhs[0]);
M=mxGetM(prhs[0]);
N=mxGetN(prhs[0]);
plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
outData=mxGetPr(plhs[0]);
for(i=0;i
  for(j=0;j
   outData[j*M+i]=inData[(N-1-j)*M+i];
}


-----------------------------------------------------------------------------------------------------------------------------------------------------------------------

当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。
通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的/reverse.c 1.0由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差。
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[],
     int nrhs, const mxArray *prhs[])
{
double *inData;
double *outData;
int M,N;
//异常处理
if(nrhs!=1)
  mexErrMsgTxt("USAGE: b=reverse(a)\n");
if(!mxIsDouble(prhs[0]))
  mexErrMsgTxt("the Input Matrix must be double!\n");
inData=mxGetPr(prhs[0]);
M=mxGetM(prhs[0]);
N=mxGetN(prhs[0]);
plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
outData=mxGetPr(plhs[0]);
for(i=0;i   for(j=0;j    outData[j*M+i]=inData[(N-1-j)*M+i];
}

在上面的异常处理中,使用了两个新的函数:
mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。

当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。
需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mex前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mexErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我们之所以使用Matlab,很重要的考虑是Matlab提供了相当丰富的矩阵运算函数和各种toolbox。在编制mex函数时,有时我们也会遇到一些操作,在Matlab下,只需要在mex函数里调用Matlab命令,我们就需要用到一个函数mexCallMATLAB,原型如下:
int mexCallMATLAB(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[],
                  const char *command_name);

有了前面的基础,使用这个函数就显得十分容易了。下面给出一个例程, 

// set.c
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[],
     int nrhs, const mxArray *prhs[])
{
double *inData;
mxArray *IN[1];
mxArray *OUT[1];
double *outData;
int M,N;
int i,j;
//异常处理
if(nrhs!=1)
  mexErrMsgTxt("USAGE: b=rot(a)\n");
if(!mxIsDouble(prhs[0]))
  mexErrMsgTxt("the Input Matrix must be double!\n");
//计算转置
if(mexCallMATLAB(1,OUT,1,prhs,"'"))
  mexErrMsgTxt("Error when compute!\n");
//根据输入参数数目决定是否显示
if(nlhs==0)
  mexCallMATLAB(0,IN,1,OUT,"disp");
else
  plhs[0]=OUT[0];
}


 使用下面代码测试程序

mex set.c 编译

set([1 2 3 4 5])

-------------------------------------------------------------------------------------------

打印函数:

mexPrintf()相当于matlab的disp函数,

mexPrintf函数里需要打印的部分必须用""而不能用''

 

子函数的问题:

子函数有两种方式,一种采用return值得方式返回值

另一种方式为利用参数返回值,把需要return的值直接赋给形参。

 

多个.c文件的编译:

多个.c文件中只能存在一个mexFunction函数

可用mex ('a.c','b.c','d.c')的格式编译





你可能感兴趣的:(matlab 和c混合编程-------------------基础)