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帮助文档
一、什么是MEX-file ??简单来说MEX-file是一种预编译的,用其他语言(C/C++,Fortran)编写的函数库,可以直接被Matlab调用。
??正如前面提到的,这种方式适用于两种情况:
??这两种情况用MEX-file的这种方案来解决都是非常合适的,因为这种调用方式非常方便,你需要注意地只是数据结构的转换。这种方式支持C/C++和Fortran,本文主要讲C/C++。
- 程序中有一部分代码耗时巨大,想通过改写这部分函数提高速度
- 已经有大量C/C++或Fortran的函数库,想直接用Matlab调用,避免重复开发
??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,达到返回数据的目的。
三、输入数据操作 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) 会得到如下图所示的结果。
文章图片
??程序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
文章图片
文章图片
??对输入数据进行操作,需要通过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]
文章图片
执行行列转置:outData[j*M+i] = inData[i*M+j];
文章图片
??当然,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
推荐阅读
- 【生信技能树】R语言练习题|【生信技能树】R语言练习题 - 中级
- 一起来学习C语言的字符串转换函数
- C语言字符函数中的isalnum()和iscntrl()你都知道吗
- SpringBoot调用公共模块的自定义注解失效的解决
- C语言浮点函数中的modf和fmod详解
- C语言中的时间函数clock()和time()你都了解吗
- thinkphp|thinkphp 3.2 如何调用第三方类库
- C语言学习|第十一届蓝桥杯省赛 大学B组 C/C++ 第一场
- 分享!如何分分钟实现微信扫二维码调用外部浏览器打开指定页面的功能
- C语言解方程的根和判断是否是闰年