zoukankan      html  css  js  c++  java
  • MATLAB中mexFunction函数的接口规范

    MEX文件的调用极为方便,其调用方式与MATALAB的内建函数完全相同,只需要在命令窗口内输入对应的文件名称即可。

       C语言MEX程序代码文件有计算子例程(Computational routine)和接口子程序(GatWay routine)两个相互独立的子程序组成。其中,计算子例程的功能是完成所需要的计算,它和具有相同功能的一般C源程序文件相同;接口子程序的功能则是计算子程序和MATALAB的接口,用户实现两个不同内存空间中的通信。

    void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
    nlhs:输出参数数目   (Left-hand side)
    plhs:指向输出参数的指针 
    nrhs:输入参数数目 
    例如,使用
    [a,b]=test(c,d,e)
    调用mex函数test时,传给test的这三个参数分别是 prhs[0]=c ,prhs[1]=d ,prhs[2]=e 
    当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。  
    细心的你也许已经注意到,prhs[i]和plhs[i]都是指向类型mxArray类型数据的指针。 这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。 
    为了让大家能更直观地了解参数传递的过程,我们把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! "); 
    else 
      mexPrintf("大家好! "); 
    }
    将这个程序编译通过后,执行hello(1),屏幕上会打出: 
              hello,world! 
    而hello(0)将会得到: 
               大家好! 
    现在,程序hello已经可以根据输入参数来给出相应的屏幕输出。在这个程序里,除了用到了屏幕输出函数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[]) 

    double *i; 
    i=mxGetPr(prhs[0]); 
    if(i[0]==1) 
      mexPrintf("hello,world! "); 
    else 
      mexPrintf("大家好! "); 
    }  
    这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。
    但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢 ?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就 
    没法对它进行计算。 
    为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数 和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来: 
    //show.c 1.0 
    #include "mex.h" 
    #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<M;i++) 
    {   for(j=0;j<N;j++) 
         mexPrintf("%4.3f  ",data[j*M+i]); 
         mexPrintf(" "); 
      }

    编译完成后,用下面的命令测试一下: 
      a=1:10; 
      b=[a;a+1]; 
      show(a) 
      show(b) 
    需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i] 。 
    输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下: 
       mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag) 
       m:待申请矩阵的行数 
       n:待申请矩阵的列数 
    为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用 mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输  

     1 //reverse.c 1.0 
     2 #include "mex.h" 
     3 void mexFunction(int nlhs, mxArray *plhs[], 
     4     int nrhs, const mxArray *prhs[]) 
     5 { 
     6 double *inData; 
     7 double *outData; 
     8 int M,N; 
     9 int i,j; 
    10 inData=mxGetPr(prhs[0]); 
    11 M=mxGetM(prhs[0]); 
    12 N=mxGetN(prhs[0]); 
    13 plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL); 
    14 outData=mxGetPr(plhs[0]); 
    15 for(i=0;i<M;i++) 
    16   for(j=0;j<N;j++) 
    17    outData[j*M+i]=inData[(N-1-j)*M+i]; 
    18 } 
    View Code

    当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。 
    通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差,以下程序则容错性较好

     1 #include "mex.h" 
     2 void mexFunction(int nlhs, mxArray *plhs[],  int nrhs, const mxArray *prhs[]) 
     3 { 
     4 double *inData; 
     5 double *outData; 
     6 int M,N; 
     7 //异常处理 
     8 //异常处理 
     9 if(nrhs!=1) 
    10     mexErrMsgTxt("USAGE: b=reverse(a)
    "); 
    11   if(!mxIsDouble(prhs[0])) 
    12    mexErrMsgTxt("the Input Matrix must be double!
    "); 
    13    inData=mxGetPr(prhs[0]); 
    14    M=mxGetM(prhs[0]); 
    15    N=mxGetN(prhs[0]); 
    16    plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL); 
    17    outData=mxGetPr(plhs[0]); 
    18    for(i=0;i<M;i++) 
    19      for(j=0;j<N;j++) 
    20      outData[j*M+i]=inData[(N-1-j)*M+i]; 
    21   }
    View Code

    在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。 
    需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mex前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。
    至此为止,使用C编写mex函数的基本过程已经介绍完了。

  • 相关阅读:
    SPOJ GSS4 Can you answer these queries IV ——树状数组 并查集
    SPOJ GSS3 Can you answer these queries III ——线段树
    SPOJ GSS2 Can you answer these queries II ——线段树
    SPOJ GSS1 Can you answer these queries I ——线段树
    BZOJ 2178 圆的面积并 ——Simpson积分
    SPOJ CIRU The area of the union of circles ——Simpson积分
    HDU 1724 Ellipse ——Simpson积分
    HDU 1071 The area ——微积分
    HDU 4609 3-idiots ——FFT
    BZOJ 2194 快速傅立叶之二 ——FFT
  • 原文地址:https://www.cnblogs.com/haoyul/p/5606720.html
Copyright © 2011-2022 走看看