一、选择matlab:
注意。Matlab的安装需要较长时间,建议本拓展在同学们自己的电脑上运行。
Matlab是大多数工科学生必修的科目,是一个口碑极佳的数学计算工具,可以支持立即运算和程序设计两种形式。Matlab较新的版本均提供32位版本和64位版本。在安装时,32位操作系统只能安装32位matlab,64位操作系统最好安装64位matlab,但是也能安装32位matlab。
本教程将学习使用VC++6.0与matlab交互,而VC++6.0所编译的程序,也就是我们所写的代码,经过编译以后,是32位的,故只能和32位matlab进行交互。若将来使用高版本的VC++,编译出64位可执行程序,则就可以和64位matlab交互了。本教程以matlab2014作为连接对象。
首先来简单安装32位matlab。使用虚拟光驱(网盘中提供)加载iso文件,在统中找到matlab2014安装目录,里面有两个子目录,Win32和Win64。找到Win32目录以安装32位的Matlab。
安装时会提示存在64位版本。这里忽略提示,一直点击下一步可安装到结束。程序安装需要较长时间。注意,在同一个Windows系统中允许同时存在W32版本和W64版本的Matlab。所以若你的系统是64位系统,则不必重新安装操作系统。
二、应用程序与matlab的交互
首先先给出定义:将开发者的电脑叫做开发电脑,将最终程序将要运行的电脑叫做发布电脑,将开发者开发的程序叫做应用程序。在大多数情况下,开发电脑和发布电脑是不同的电脑平台,其上安装的软件也不同。应用程序与matlab的交互大致有以下3种形式:
- 同时打开应用和Matlab,在应用程序中动态调用matlab的接口,将计算任务交给matlab执行,执行完毕后将结果返回给应用程序。这种方式需要在发布电脑上安装完整版的matlab,而且应用程序第一次调用matlab模块时需要启动matlab,会有较大的延时。总的来说,这种方式叫做远程进程调用(Remote Process Call ,RPC调用)。由于应用程序和被调用的matlab都在同一台发布电脑上,因此这种调用方式又被称为本地进程调用(LPC,Local Process Call)。
- 使用matlab将应用程序所需要的模块编译成小的授权发布模块。这样应用程序执行时不需要启动整个matlab,只需要启动这个授权发布的模块即可。显然这种方式最大的优点是matlab 是安装在开发电脑上的,发布电脑不需要完整的matlab,只需要开发者向matlab购买一个发布授权即可——当然破解版不在讨论之列。此外由于发布电脑上安装的是轻量级Matlab,因此启动和资源消耗都比较少。这种模式的缺点也是很明显的。由于发布电脑上一般没有命令解释模块,因此应用程序的灵活性被降低了,只能执行事先编译好的matlab代码。这种调用方式叫做嵌入式matlab模块(embedded matlab module)
- 编写可以被matlab调用的应用程序模块。应用程序仅仅提供模块而是否调用,如何调用,由matlab决定。这种调用方式叫做mex编程。应用程序不用编写main函数,仅仅向matlab提供被调用代码。这种方式显然在发布电脑上需要安装完整版的matlab。使用应用程序来补充matlab的不足,这是一种面向matlab 的解决方案。
本拓展仅介绍第一种LPC调用方式。
首先找到matlab的对外接口的目录:在matlab的安装目录下可以找到对外接口目录:
其中Include目录是C语言的接口头文件。Lib目录是matlab与C接口的库文件。进入lib可以发现有32位和64位两种方式,我们现在使用的C编译器是VC6.0,是生成32位系统的,因此这里库文件要注意只能连接32位目录下的库。反之,若使用高版本的VC,例如VS2014,则可以编译64位应用程序,这时候就应该选择对应的库文件。
三、使用VC++编写应用程序在线调用matlab
工程路径设置
在WinLearn中创建新的项目,项目名叫做WinStep6。由于仅仅测试调用matlab功能,因此不用建立Win32 Application,建立我们学习C语言时所习惯的Win32 Console Application即可。按照C语言习惯,选择空工程。
工程建好以后,需要对系统路径做一些设置。在Tools菜单中选择Options。然后在选项卡中找到Directorys:
首先确定是设置包含文件(include)目录。然后点击新建按钮,创建一行新的包含文件路径。出现编辑框后,点击右边的…按钮如图上的(1)步骤。
出现右边的“选择目录”对话框后,先点击地下的Drive,选择matlab的安装后的所在磁盘号。如果前面都是选择默认安装,这里应该是C盘。然后在从路径中找到matlab的外部支持的include目录。如上图3.选择好目录后点击OK使设置生效。
然后需要设置库文件所在目录。类似包含文件目录的设置,这里要选择library files。如下图。注意在lib中要选择Win32,再选microsoft。因为你现在编写的应用程序是microsoft公司的VC++6.0。若你用其他公司的C编译器,则选择对应的路径。
打开和关闭matlab
在刚才的空工程文件中,新建一个源文件,main.c。在头文件位置包含”engine.h”。并使用#pragma命令将libeng.lib包含到工程里。代码如下:
其中几处需要注意的地方:
a. 第一个包含文件是windows.h,对于本例并不需要,但是后面的继续内容可能需要此头文件。
b. <stdio.h>提供了printf函数的声明
c. <stdlib.h>提供了exit函数的声明
d. <tchar.h>提供了UNICODE和ASC两种模式下中文字符的输入和输出的兼容性。下面代码中的printf前面冠以_t和字符串冠以_T( ),用于两种编码方式的兼容性。
e. <engine.h>不是VC提供的头文件,位于Matlab的安装目录下。
但是因为在前面的操作中已经将其添加到VC的包含文件的目录里面,因此可以将其当做系统头文件来用。
f. #pragma是微软公司特有的预处理命令,这里表示将使用到libeng.lib库。后面会根据matlab的调用的功能,增加新的库连接。
g. engOpen和engClose是成对使用。前者打开matlab,若是第一次打开,将会等待一段时间。并且matlab会打开一个小窗口。
h. 在跨架构(例如在64位操作系统上运行32位matlab或者操作系统中同时存在两个以上matlab版本)或者系统经常安装卸载程序时,上述程序有可能不能正常运行。一种常见的错误信息如下:
若遇到此错误,需要按照下面的步骤在系统中添加32位matlab的执行路径:
点出编辑界面后,选添加再选浏览,找到C盘下的matlab安装路径再找到bin下的win32,点击确定后关闭编辑界面保存。如有必要重启电脑即可。
程序正确运行时,会弹出一个matlab命令窗口:随版本不同输出信息各不相同。
向matlab传递变量:
Matlab中变量即数组,哪怕是一个变量也是以数组形式保存的。C语言使用mxArray类型和matlab数组进行交互。要使用mxArray,需要在头文件里包含mxlib.h,并且需要连接libmx.lib库。代码如下:
其中几处需要注意的地方:
a. 头文件增加了matrix.h
b. 库文件增加了libmx.lib
c. 主要matlab的代码是s=randperm(n);表示将1~n的整数乱序(洗牌)这里的n值将由应用程序传入,而s将传出给应用程序。从示例代码中可以发现传入参数是一个普通字符串,如果需要,可以先由用户输入或者程序中生成有效的matlab代码,然后在这里传入。
d. C语言和Matlab引擎的数据通道是mxArray,用来传入数据和传出数据。
e. mxArray支持复杂的数据类型,可以搜索mxCreateXXXXMatrix的函数簇。这里用mxCreateDoubleMatrix演示了双精度浮点数。其前两个参数1,1表示是1*1的矩阵,是一个简单的变量。类似于malloc,mxCreateXXXXMatrix内部将分配矩阵所需要的存储空间,因此和应用程序使用的变量是两个不同的空间。下面使用memcpy函数将应用程序的变量n值复制到mx的空间里。同样,类似于malloc, mxCreateXXXXMatrix函数分配的内存,在使用完毕后要使用mxDestroyArray函数释放。
f. 使用engPutVariable将mx变量(矩阵也是一种变量)放置到matlab工作区间内。其中第二个参数是变量名,第三个参数是mx矩阵。
使用engGetVariable可以将变量从matlab中取出存放到mx变量空间。该函数返回一个mxArray数据,可以通过mxGetPr获得这个mxArray内存地址。由于Matlab默认都是double类型,因此可以将指针赋给pRes指针。
g. 使用mxGetN获得矩阵的列,使用mxGetM获得矩阵的行。(在matlab中矩阵是按照先行后列的方式保存的。)
h. 区分一下:pIn是由mxCreateXXXX函数簇创建的,因此需要mxDestroyMatrix释放内存;而pOut是由engGetVariable获得的,因此不需要mxDestroyMatrix。在最后由engClose关闭时自动释放内存。