220 likes | 523 Views
工作总结. 范志先 2006.5.14. 摘要. 应用 c/c++ 语言调用 scilab 应用 tcl 脚本调用 c/c++ 函数. 应用 c/c++ 语言调用 scilab 函数. 使用 c 语言和 c ++语言调用 scilab 的区别不大,就是调用 dll 的问题。. 使用 c 语言调用 scilab 的函数过程.
E N D
工作总结 范志先 2006.5.14
摘要 • 应用c/c++语言调用scilab • 应用tcl脚本调用c/c++函数
应用c/c++语言调用scilab函数 • 使用c语言和c++语言调用scilab的区别不大,就是调用dll的问题。
使用c语言调用scilab的函数过程 • 首先需要连入libscilab库,可以使用以下预处理语句:#pragma comment(lib, “debug/libScilab.lib”),在程序连入libscilab库的时候,同时需要连入lapack.dll、arpack.dll等几个scilab 的bin目录下的库,所以需要同时将所需的几个dll文件都放到exe文件所在目录下。
,外部引入以下几个函数 • extern int StartScilab(char *SCIpath,char *ScilabStartup,int *Stacksize); • extern int TerminateScilab(char *ScilabQuit); • extern int SendScilabJob(char *job); • extern void C2F(tmpdirc)(void);
在主函数中启动scilab环境 • if ( StartScilab(NULL,NULL,NULL) == FALSE ) printf("Error : StartScilab \n"); • 经测试证明这里的启动,并不是说启动了scilab,运行时进程中并没有wscilex.exe。 • 把程序移植到没有装scilab的机子上试验,程序照常运行,再次说明了程序完全可以脱离scilab环境运行。
现在就可以定义自己的函数了 • 几点说明: • 1,矩阵是以一维数组的形式存储的。注意scilab里是按列存储的。所以需要首先定义一个数组变量。然后调用WriteMatrix函数来定义scilab环境的矩阵变量。该函数定义在stack-c.h文件内。WriteMatrix("A", &mA, &nA, A); “A”为矩阵变量,mA为列数,nA为行数,A为数组变量。
2,应用SendScilabJob可以向scilab发送指令了如:flag=SendScilabJob(“[u,v,w]=svd(A);”);flag=0则执行成功,非零不成功。2,应用SendScilabJob可以向scilab发送指令了如:flag=SendScilabJob(“[u,v,w]=svd(A);”);flag=0则执行成功,非零不成功。 • 3,执行完毕后,再由scilab矩阵形式转变为数组:由函数GetMatrixptr("u", &m, &n, &lp);第一个参数为预转变数组的矩阵变量,m为矩阵的列数,n为矩阵的行数。cxtmp=(double*)malloc((m*n)*sizeof(double)); 分配一维数组空间。再由函数ReadMatrix("u", &m, &n, cxtmp);将矩阵数据输入到数组中。
程序结束,退出scilab环境 • if ( TerminateScilab(NULL) == FALSE ) printf("Error : TerminateScilab \n");
清空scilab环境中的所有临时变量 • C2F(tmpdirc)();
需要注意的几点问题: • 启动scilab环境时需要读取文件scilab.star,该文件内定义了启动scilab所必须的lib文件,包括elem,peicent,util。这三个文件夹在macros目录下,需要将其拷贝到程序目录里。
同时还需要将tcl目录拷贝到程序目录里以启动tcl脚本。不使用tcl脚本,程序仍然可以执行。但是会有警告提示。程序测试证明启动tcl脚本程序的速度会放慢将近一倍的时间。同时还需要将tcl目录拷贝到程序目录里以启动tcl脚本。不使用tcl脚本,程序仍然可以执行。但是会有警告提示。程序测试证明启动tcl脚本程序的速度会放慢将近一倍的时间。
应用tcl脚本调用c函数 • 目的:我们的目的就是将应用程序分为三个层次来实现,一个是输入输出层这个可以应用MFC或者是gtk等等开发工具来编制图形界面,或者是命令行的形式;一个是tcl脚本的调用层,在这个层次上,我们从输入输出层接受到命令指令字符串,然后解析;第三个层面就是我们的核心代码层,也就是我们所说的程序内核。对应用程序做了这三个层次上的划分以后,我们就可以很容易对程序进行维护、扩充等,以实现版本的升级。
为了实现这一目的我们今天讲解一个简单的tcl调用c函数的例子:为了实现这一目的我们今天讲解一个简单的tcl调用c函数的例子:
步骤: • 环境 : • 要包含的头文件是<tcl.h>,在这个头文件里包含了我们今天要用到的Tcl_Interp *interp;在Tcl的数据结构中的核心是Tcl_Interp.一个解释器包含了一 套命令,一组变量和一些用于描述状态的东西。每一个 Tcl命令是 在特定的Tcl_Interp中运行的,基于Tcl的应用程序可以同时拥有几 个Tcl_Interp。Tcl_Interp是一个轻量级的结构,可以快速的新建 和删除。 • 这一节介绍Tcl_Interp的东东是从网上找的,暂时还不明白它到底是干什么用的。不要管那么多了,你只要记住需要包含<tcl.h>头文件就是了。以后再查资料弄明白吧。
需要声明几个必须的函数: • int Hello_Init(Tcl_Interp *interp); • int tHelloCmd(ClientData clientData, Tcl_Interp *interp, int argc,char *argv[]); • int Hello(); //这就是你调用的c函数啦 • 前两个函数到底是什么意思,干什么用的,别着急,先看看是怎么定义它的吧。
函数的定义: • int Hello_Init(Tcl_Interp *interp) • { • HINSTANCE hDll; • hDll=LoadLibrary("tcl84.dll"); • TCL_CreateCommand tclcreatecommand; • tclcreatecommand = (TCL_CreateCommand)GetProcAddress(hDll, "Tcl_CreateCommand"); • //上两句干吗的?不多说了,就是从tcl84.dll中找出Tcl_CreateCommand函数来 • tclcreatecommand(interp,"h",(Tcl_CmdProc*)tHelloCmd,(ClientData)NULL,(Tcl_CmdDeleteProc *) NULL);//这一句就是将我们想要得命令字符串和tHelloCmd函数联系起来拉 • return TCL_OK; • }
//在这个函数里就要调用我们自己的c语言函数了!!//在这个函数里就要调用我们自己的c语言函数了!! • int tHelloCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) • { • int retval = 0; • retval = Hello();//就是这里!!!!!!!!! • if (retval == 1) • { • printf("SUCCESS!!!\n"); • } • else • { • printf("FAILURE !!!\n"); • } • return TCL_OK; • }
//这就是我们的函数了!!!!!! • int Hello() • { • int ln; • printf("ok\n"); • printf("input: "); • scanf("%d", &ln); • printf("ln: %d\n", ln); • return 1; • }
定义主函数 • int main(int argc, char *argv[]) • { • HINSTANCE hDll; • hDll=LoadLibrary("tcl84.dll"); • TCLMAIN tclmain; • tclmain = (TCLMAIN)GetProcAddress(hDll, "Tcl_Main"); • //就是要取tcl84.dll中的Tcl_Main啊! • tclmain(argc, argv, Hello_Init); 取出来调用了。 • exit (0); • }
让我们回过头来看一下到底是哪些函数调用了哪些函数让我们回过头来看一下到底是哪些函数调用了哪些函数