Matlab调用C语言mexFunction入口函数


文章目录

    • 一、什么是MEX-file
    • 二、如何创建可供Matlab直接调用的MEX-file
        • 1.安装Matlab支持的C/C++编译器
        • 2.创建.c/.cpp文件
    • 三、输入数据操作
        • 1、传入整数类型数据
        • 2、传入double类型数据
        • 3、传入矩阵类型数据
    • 四 、输出数据操作
  • 参考资料

??Matlab与C/C++混合编程有很多种方式,分别适用于不同的情况。
  • 程序主体用Matlab编写,有一些特别耗时的函数用C/C++改写来提高效率,或者已经有现成的C/C++函数,应用到Matlab程序中(本文属于这种情况)
  • 程序主体用C/C++编写,部分程序想调用Matlab函数减少开发时间,本文不涉及这种情况,建议读者自行查阅Matlab帮助文档
??Matlab 可以调用C编译器编译的C程序,通过MEX文件的调用,其调用方式与MATALAB的内建函数完全相同,只需要在命令窗口内输入对应的文件名称即可。
一、什么是MEX-file ??简单来说MEX-file是一种预编译的,用其他语言(C/C++,Fortran)编写的函数库,可以直接被Matlab调用。
??正如前面提到的,这种方式适用于两种情况:
  • 程序中有一部分代码耗时巨大,想通过改写这部分函数提高速度
  • 已经有大量C/C++或Fortran的函数库,想直接用Matlab调用,避免重复开发
??这两种情况用MEX-file的这种方案来解决都是非常合适的,因为这种调用方式非常方便,你需要注意地只是数据结构的转换。这种方式支持C/C++和Fortran,本文主要讲C/C++。
??C语言MEX程序代码文件有 计算子例程(Computational routine)和接口子程序(GatWay routine)两个相互独立的子程序组成。其中,计算子例程 的功能是完成所需要的计算,它和具有相同功能的一般C源程序文件相同;接口子程序 的功能则是计算子程序和MATALAB的接口,用户实现两个不同内存空间中的通信。
二、如何创建可供Matlab直接调用的MEX-file 1.安装Matlab支持的C/C++编译器 2.创建.c/.cpp文件 ??这一步可以用Matlab的编辑器也可以用其他你喜欢的编辑器,需要注意的是: 将来在Matlab中调用的函数名即为此处你创建的文件名,而不是文件内的函数名
??MEX-file的内容,一个完整的MEX-file应该包括:
  • #include MEX-file头文件
  • mexFunction 入口函数(C/C++中的main函数)
  • 输入输出的数据的校验
  • 变量的传递
  • 你自己编写的功能函数
  • mexFunction 入口函数
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) nlhs:函数左侧,输出参数数目(Left-hand side) plhs:函数左侧,指向输出参数的指针 nrhs:函数右侧,输入参数数目 prhs:函数右侧,指向输入参数的指针

例如,使用
[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里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Api guide.pdf里的介绍。
三、输入数据操作 1、传入整数类型数据 ??为了让大家能更直观地了解参数传递的过程,我们把hello.c改写一下,使它能根据输 入参数的变化给出不同的屏幕输出:
//hello.cpp 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"); }

??在matlab命令窗口中输入: mex hello.cpp 进行编译后,然后在输入命令:hello(1) 和 hello(0) 会得到如下图所示的结果。
Matlab调用C语言mexFunction入口函数
文章图片

??程序hello已经可以根据输入参数来给出相应的屏幕输出。在这个程序里,除了用到了屏幕输出函数mexPrintf(用法跟c里的printf函数几乎完全一样)外,还用到了一个函数mxGetScalar,调用方式如下:
i=mxGetScalar(prhs[0]);

【Matlab调用C语言mexFunction入口函数】??"Scalar"就是 标量 的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整型变量i i i。既然有标量,显然还应该有矢量,否则矩阵就没法传了。看下面的程序:
2、传入double类型数据
#include "mex.h" void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { double *i; i=mxGetPr(prhs[0]); //get input parameter if(i[0]==1) mexPrintf("hello,world!\n"); else mexPrintf("大家好!!!!\n"); }

??在上面的程序中,通过mxGetPr函数从指向 mxArray 类型数据的 prhs[0] 获得了指向 double类型 的指针。
3、传入矩阵类型数据 ??如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢 ?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就 没法对它进行计算。
??为了解决这个问题,Matlab提供了两个函数 mxGetM 和 mxGetN来获得传进来参数的行数 和列数。下面程序的功能,就是获得输入的矩阵,把它在屏幕上显示出来:
#include "mex.h"void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { double *data; int M, N; int i, j; data = https://www.it610.com/article/mxGetPr(prhs[0]); //获得指向矩阵的指针 M = mxGetM(prhs[0]); //获得矩阵的行数 N = mxGetN(prhs[0]); //获得矩阵的列数 for (i=0; i

Matlab调用C语言mexFunction入口函数
文章图片

Matlab调用C语言mexFunction入口函数
文章图片

??对输入数据进行操作,需要通过MEX函数mxGetPr 得到数据的指针地址。 mxGetM 和 mxGetN 得到矩阵数据的行和列 (返回整数)。对于实矩阵,我们可以定义double *data 来对实矩阵数据操作(不过似乎是,plhs, prhs都是指向double类型的指针,所以data定义成double*类型的)
??需要注意的是,MATLAB矩阵数据的存储顺序是"从上到下,从左到右",(即按列存取)。另外,MATLAB的指标从1开始,C的指标从0开始,也就是说对于 MATLAB 的m × n m \times n m×n 的矩阵 A。 A(1,1) 就是 *data,A(2,1) 就是 *(data+1) ,以此类推,A(i, j) 就是 (data+ m(j-1) + (i-1)).
四 、输出数据操作 ??输入数据是在函数调用之前已经在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的基础上稍作改变得到的,功能是将输入的矩阵进行逆操作。
#include "mex.h"void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { double *inData; double *outData; int M,N; int i,j; if(nrhs!=1)//输入参数的个数为0 mexErrMsgTxt("USAGE: b=reverse(a)\n"); if(!mxIsDouble(prhs[0]))//输入的参数不是double型 { mexErrMsgTxt("the Input Matrix must be double!\n"); } else { inData = https://www.it610.com/article/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

执行列的逆序排列:outData[j*M+i] = inData[(N-1-j)*M+i]
Matlab调用C语言mexFunction入口函数
文章图片

执行行列转置:outData[j*M+i] = inData[i*M+j];
Matlab调用C语言mexFunction入口函数
文章图片

??当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。
??需要说明的是,Matlab提供的API中,函数前缀有mex-mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mex前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mexErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。
至此为止,使用C编写mex函数的基本过程已经介绍完了。
参考资料
  • MATLAB中mexFunction函数的接口规范https://blog.csdn.net/yshshhgxq/article/details/91351535
  • Matlab与C/C++混合编程 Matlab调用C函数https://www.cnblogs.com/ynnie/p/9239347.html

    推荐阅读