与C中的main函数一样,MEX程序中的开始函数为mexFunction.默认变量参数是:
  1. void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
其中
nlhs输出参数数目
plhs[]指向输出参数的指针
nrhs输入参数的数目
prhs[]指向输入参数的指针
例如:使用[a,b]=test(c,d,e)
 调用mex函数test时,传给test的这三个参数分别是prhs[0]=c ,prhs[1]=d ,prhs[2]=e
prhs[i]和plhs[i]都是指向类型mxArray类型数据的指针。 这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。
把hello.c改写一下,使它能根据输入参数的变化给出不同的屏幕输出:
  1. //hello.c 2.0
  2. #include "mex.h"
  3. void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
  4. {
  5. int i;
  6. i=mxGetScalar(prhs[]);
  7. if(i==)
  8. mexPrintf("hello,world!\n");
  9. else
  10. mexPrintf("大家好!\n");
  11. }

将这个程序编译通过后,执行hello(1),屏幕上会打出:
hello,world!
而hello(0)将会得到:
大家好!
现在,程序hello已经可以根据输入参数来给出相应的屏幕输出。在这个程序里,除了用到了屏幕输出函数mexPrintf(用法跟c里的printf函数几乎完全一样)外,还用到了一个函数:mxGetScalar,调用方式如下:
i=mxGetScalar(prhs[0]);
"Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。既然有标量,显然还应该有矢量,否则矩阵就没法传了。看下面的程序: 

  1. //hello.c 2.1
  2. #include "mex.h"
  3. void mexFunction(int nlhs, mxArray *plhs[],
  4. int nrhs, const mxArray *prhs[])
  5. {
  6. int *i;
  7. i=mxGetPr(prhs[]);
  8. if(i[]==)
  9. mexPrintf("hello,world!\n");
  10. else
  11. mexPrintf("大家好!\n");
  12. }

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

  1. //show.c 1.0
  2. #include "mex.h"
  3. #include "mex.h"
  4. void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
  5. {
  6. double *data;
  7. int M,N;
  8. int i,j;
  9. data=mxGetPr(prhs[]); //获得指向矩阵的指针
  10. M=mxGetM(prhs[]); //获得矩阵的行数
  11. N=mxGetN(prhs[]); //获得矩阵的列数
  12. for(i=;i<M;i++)
  13. { for(j=;j<N;j++)
  14. mexPrintf("%4.3f ",data[j*M+i]);
  15. mexPrintf("\n");
  16. }
  17. }

编译完成之后,用下面的命令测试一下:

  1. a=:;
  2. b=[a;a+];
  3. show(a)
  4. show(b)

需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为0,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i]。

输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数mxCreateDoubleMatrix来实现内存的申请,函数原型如下:

  1. 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[]);
  11. M=mxGetM(prhs[]);
  12. N=mxGetN(prhs[]);
  13. plhs[]=mxCreateDoubleMatrix(M,N,mxREAL);
  14. outData=mxGetPr(plhs[]);
  15. for(i=;i<M;i++)
  16. for(j=;j<N;j++)
  17. outData[j*M+i]=inData[(N--j)*M+i];
  18. }

当然,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!=)
  10. mexErrMsgTxt("USAGE: b=reverse(a)\n");
  11. if(!mxIsDouble(prhs[]))
  12. mexErrMsgTxt("the Input Matrix must be double!\n");
  13. inData=mxGetPr(prhs[]);
  14. M=mxGetM(prhs[]);
  15. N=mxGetN(prhs[]);
  16. plhs[]=mxCreateDoubleMatrix(M,N,mxREAL);
  17. outData=mxGetPr(plhs[]);
  18. for(i=;i<M;i++)
  19. for(j=;j<N;j++)
  20. outData[j*M+i]=inData[(N--j)*M+i]; //总之,在C中,二维数组也是按照一维处理的
  21. }

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

在函数内部调用时,常用函数用法如下:
 
  1. mxIsNumeric(prhs[]); // 判断变量是否是数字
  2. mxIsDouble(prhs[]); // 判断变量是否为双精度
  3. mxIsEmpty(prhs[]); // 判断变量是否为空值
  4. mxIsComplex(prhs[]); // 判断变量是否为复数
  5. mexPrintf("%d", y); // 命令行中打印数据
  6.  
  7. x = mxGetN(prhs[]); // 获取输入参数的行数
  8. y = mxGetM(prhs[]); // 获取输入参数的列数
  9. points = mxGetScalar(prhs[]); // 将返回变量的实部,为双精度形数据
  10. plhs[]= mxCreateDoubleMatrix(, , mxREAL); // 创建1×1双精度返回变量
  11.  
  12. x = mxGetData(prhs[]); // 获取变量的指针,功能相当于mxGetPr()
  13. y = mxGetPr(plhs[]); // 获取变量的指针,数据为实数
对mexFunction的参数是进行指针操作的,不能用单纯的return返回值。MEX程序传送回来的整数数据要变为双精度型数据,才能为其它函数所处理。
注意:mxarray stores data in one dimension , even its a matrix
if your c program is preparing a matrix for matlab, it need to be reshaped into one D
if your c program is getting data out of matlab, you need to convert yourself to become a meaningful data 
 
matlab的数组在C中都按照一维存储的但是这并不影响mxGetM,mxGetN,mxGetDimensions得到数据在matlab中的维度,如果matlab中输入的数据是4行5列的数据,mxGetM得到的就是4,mxGetN得到的就是5
但是在运算时必须按照1维的来运算,例如还是假设你输入的是4行5列的矩阵,你这里得到
int mBB = mxGetM(prhs[0]); // 行数mBB为4
int nBB = mxGetN(prhs[0]); // 列数nBB为5
double *bb = mxGetPr(prhs[0]); // 得到矩阵中数据的指针
这个时候如果你想调用原矩阵中3行2列的元素,即matlab中的bb(3,2),也即bb(4*(2-1)+3)也就是bb(7);那么在C中应该对应的是bb[mBB*(2-1)+(3-1)]也就是b[7-1],也就是bb[6](从这可以看出,是按照列数的)
 
 
 
 
 
 

MEX程序中的mexFunction函数【转】的更多相关文章

  1. 在一个C程序中,main()函数可以放在哪?

    C语言规定,在一个C程序中,main()函数的位置(). A.必须在系统调用的库函数之后 B.必须在程序的开始 C.必须在程序的最后 D.可以在任意位置 答案:D [解析] 每个C程序有且只有一个主函 ...

  2. Linux上从Java程序中调用C函数

    原则上来说,"100%纯Java"的解决方法是最好的,但有些情况下必须使用本地方法.特别是在以下三种情况: 需要访问Java平台无法访问的系统特性和设备: 通过基准测试,发现Jav ...

  3. MFC程序中消息以及函数的处理顺序简介[转]

    MFC应用程序中处理消息的顺序 1.AfxWndProc()      该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc 2.AfxCallWndProc()  该 ...

  4. 从Win32程序中的主函数中获取命令行参数

    在标准C或者Win32控制台程序的main函数中,它们都有两个参数:"argc" 和 "argv",如下所示: int main(int argc, char ...

  5. 小程序中使用async函数 会报 regeneratorRuntime is not defined的问题

    async await比Promise更好的解决异步操作问题,但是在小程序中直接使用会出现以下的错误提示 是因为缺少了regeneratorRuntime这个模块,需要从外部引入 1.在新建的文件夹中 ...

  6. C语言中的可变参数函数的浅析(以Arm 程序中的printf()函数实现为例) .

    我们在C语言编程中会遇到一些参数个数可变的函数,一般人对它的实现不理解.例如Printf(): Printf()函数是C语言中非常常用的一个典型的变参数函数,它 的原型为: int printf( c ...

  7. 程序中使用now()函数对性能的影响

    这两天从某平台的慢查询日志中发现了一些很简单的,原本执行时间在0.01-0.03s的SQL,慢查询日志中记录的执行时间在2s左右. 排查后发现,表设计及索引建设均没有什么问题.但是SQL语句中使用了n ...

  8. 程序中图片透明 函数(使用SetBkColor API函数)

    void DrawTransparentBitmap(HDC  hdc,  HBITMAP  hBitmap,  short  xStart,  short  yStart,  COLORREF  c ...

  9. PHP采集程序中的常用函数

随机推荐

  1. LeetCode初级算法的Python实现--排序和搜索、设计问题、数学及其他

    LeetCode初级算法的Python实现--排序和搜索.设计问题.数学及其他 1.排序和搜索 class Solution(object): # 合并两个有序数组 def merge(self, n ...

  2. Java基础——NIO(二)非阻塞式网络通信与NIO2新增类库

    一.NIO非阻塞式网络通信 1.阻塞与非阻塞的概念  传统的 IO 流都是阻塞式的.也就是说,当一个线程调用 read() 或 write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在 ...

  3. 结合《需求征集系统》谈MVC框架

    结合<需求征集系统>分析MVC框架. 六个质量属性: 可用性:在系统压力过大时,会提示系统繁忙. 可修改性:使用配置文件,修改配置文件即可.对于一些公共的方法,进行封装,修改时,只需修改封 ...

  4. QImage对一般图像的处理

    QImage对一般图像的处理 Qt中QImage类封装了对于一般图像像素级的操作,图像显示则使用QPixmap. 本文说说对一般图像(常见格式,图像不大)的处理,比如将彩色图像处理为灰度图像.首先要获 ...

  5. 华为LiteOS系统使用-任务调度函数-第一篇

    1.最近项目遇到华为的LiteOS小型操作系统,使用学习 2. 先打开一个工程LiteOS_Kernel-master\projects\LPC824_LITE_KEIL 3. main.c里面2个关 ...

  6. * 197. Permutation Index【LintCode by java】

    Description Given a permutation which contains no repeated number, find its index in all the permuta ...

  7. 【转】unity3d 资源文件从MAX或者MAYA中导出的注意事项

    转自游戏开发主席   1.首先,Unity3d 中,导出带动画的资源有2种导出方式可以选择:    1) 导出资源时,只导出一个文件,保留模型,骨骼和所有的动作帧(把所有的动作,比如idle,atta ...

  8. python3中使用python2中cmp函数出现错误

    在python2中我们经常会使用cmp函数来比较一些东西,但是在python3中,你再来使用这个函数的时候,发现就报错了,提示找不到这个函数,这是为啥呢? 答:新版的python已经舍弃这种用法 而在 ...

  9. 【转载】java byte转十六进制

    public static String bytes2HexString(byte[] b) { String ret = ""; for (int i = 0; i < b ...

  10. str和repr

    在Python2.6和Python3.0以及更早的版本中,在交互式模式下的输出本质上是使用repr,因此对于一些浮点数运算,会显示很多位: 4 / 5.0 #0.8000000000000004 但是 ...