MATLAB与C/C++混合编程的一些总结

 

【转载请注明出处】http://www.cnblogs.com/mashiqi 

 

先上总结:

由于C/C++语言的函数输入输出参数的特点,可以将多个参数方便地传入一个函数中,但却不能方便地返回多个参数。要返回多个参数,就得用指针或者struct/class(其他的高招?)。但这些麻烦的地方在C程序的函数与函数之间是没有太大问题的,关键是不要在C与MATLAB的接口之处搞的太复杂。

但是,我们在写MATLAB代码的时候,由于变量的格式非常自由,所以我们往往都尽量把变量的格式设计成很comprehensible的形式。比如说,我写的这个能完成Adaboost算法功能的m函数adaboost_mashiqi(),它的返回值中既有向量,也有矩阵,还有结构体。这在C中看来是很复杂的,但却很直观,这些变量就该是这种形式的。甚至如果是多层树的话,还应该是链表呢!

这两段话的内容可以用如下这张图来表示。

解释一下这张图。最左边的是一个m文件,它准备调用一个用C/C++写的名为true_function()的函数。我们把这个函数的输入输出简单记为inputs和outputs,于是函数应该是这样的:

        

由于inputs和outputs都是MATLAB里面的变量们,所以它们很有可能是comprehensible的。到了mexFunction()后,首先要做的事情就是把这些comprehensible but not convenient的变量转换成C语言易于处理的convenient的变量,然后调用真正实现函数功能的true_function()函数去实现功能,最后再将这些convenient but not comprehensible的变量转换成合适与MATLAB的comprehensible的变量。

 

可是,这样做比那个不是最好的,因为mexFunction()中处理这些comprehensible but not convenient的变量可能相当麻烦。转换变量类型并非C/C++的优势,C/C++的优势在于对循环的处理极大的快于MATLAB!所以,我们有第二种方案,能避开C/C++的劣势,同时又保留C/C++的优势,这是一个两全其美的办法。请看下图:

此方案将参数转换的工作放到了MATLAB里面来做。这是绝对正确的一个方法,因为在MATLAB里面各变量之间的类型转换是相当自由的。我们来看看进行了这样的改变之后,整个过程变成了什么样。首先,主文件调用Interface()函数,参数传递都在MATLAB里面,很方便;进入Interface()函数后,在MATLAB平台上将各个变量转变为C/C++平台好处理的格式(比如说把结构体的各个成员变量分别独立传进去而不是把真个结构体作为一个整体传进去etc);现在到了mexFunction(),由于变量在Interface()里面已经经过了处理,在这里只需要再做一些trivial的处理就行了,然后直接调用true_function()来实现具体的功能。整个流程非常的easy!

 

当然,还有一些问题,比如在MATLAB中我们常常将一些控制整个算法参数的变量放进一个结构体变量options中,然后将这个结构体传入函数进行控制(比如算法最大迭代次数啊,收敛条件的epsilon大小啊等等)。这个options在上面这个框架里怎么实现呢?我在这个给出一个我的办法。首先,在Interface()之前调用options = OptionsSettings(…)函数,设定相应的控制变量,然后把这个options结构体变量随着inputs一起传入Interface()函数。在Interface()函数内部,将这个options结构体的各个成员变量单拿出来作为变量分别传入true_function()中,这样就可以了。

 

mexFunction()中一些函数总结

在mexFunction()刚开头,一般需要把存放在prhs[?]中的MATLAB格式的变量转换成C中的double, int等类型的变量,怎么做呢?如果prhs[0]中(也就是第一个input)是一个MATLAB中的scalar, vector或者matrix,那么就用mxGetPr()这个函数:

double *x_pointer = mxGetPr(prhs[0]);

对于MATLAB中的vector,通过x_pointer[0], x_pointer[1], x_pointer[2],…进行访问,对于MATLAB中的matrix,比如一个3x3的矩阵,则(1,1)的元素通过x_pointer[0]访问,(2,1)的元素通过x_pointer[1]访问,(1,2)的元素通过x_pointer[3+0]访问。对于MATLAB中的其他类型的数据,通过mxGetData()访问:

类型 *x_pointer = (类型*)mxGetData(prhs[0]);

mxGetData返回类型为void*,所以要进行类型转换。注意,mxGetPr()和mxGetData()的输入参数类型都是const mxArray*而不是mxArray*。

在mexFunction()刚开头,一般需要数据再次转回MATLAB能接受的类型,这时需要用到mxCreatDoubleMatrix()/mxCreatNumericMatrix()/mxCreatStructMatrix()等函数。举例:

                  plhs[0] = mxCreatDoubleMatrix(3,3,mxREAL);

                  double *p = mxGetPr(plhs[0]);

                  for(int i = 0; i < 10; i++) {

                       p[i] = i;

                  }

这样就完成了对plhs[0]的赋值,等返回MATLAB时,第一个output就会是(0:9)这个向量。没错,就是通过指向plhs[0]的指针p间接的像plhs[0]中赋值的。

 

博主给个example啊!

上面说的似乎都好抽象,这里给个链接,是我的一个代码,大家可以拿去看看,作为example,在我这个上面改改,练练手。但我这个代码也有一些瑕疵的。由于已经把整个代码都写完了,回过头来梳理的时候才发现这些问题,所以就懒得改了,下次注意的就是了。下面是我的代码的问题,写在这里,做个自己的一个记录吧。

 

关于我的这个代码中的变量tree的处理

在Adaboost_mashiqi()返回的结构体中,第一个成员变量tree本身也是一个结构体,不过上面已经说过,C函数之间传递参数的准则是as comprehensible as possible,所以这里处理tree的方法没有问题。问题出现在第二个出现tree的地方,就是返回给m文件的tree,这里的tree依然是一个结构体,这样就不太好了,一是变量格式转换起来不太方便,而是若以后想要给添加函数添加功能返回更多的变量,那这种情况下使用结构体也不方便。因此,可以在m文件和c文件中间在加一个m文件来完成"变量格式转换"这件事,这样既不会破环原m文件的格式,也能使得C文件的结构更容易编写与扩展。

 

如何在MATLAB和Visual Studio平台之间hybrid programming?

废话不多说,想知道如何设置Visual Studio来进行混合编程调试,点这里。另外,我用的版本是MATLAB R2012b和Visual Studio 2010,这两个是匹配的,若不是使用的这两个版本,这里在这里看您的两个版本是否匹配。

 

关于写程序的自我修养(/装逼捂脸中):

绝对不将就!

能优化就一定要优化;

能完善就一定要完善;

能写地更加优美就一定要能写地更加优美!

posted on 2015-02-07 22:47  mashiqi  阅读(1099)  评论(0编辑  收藏  举报

导航